I'm trying to write a program that in the Main
class one can initiate unknown amount of new threads.
Each thread in turn should call to a Singleton Copier
class which should call a file transfer action.
My goal is, regardless the amount of threads requests, is to limit the number of concurrent transfers to 2 transfers, so I thought solving it with Semaphore
.
My problem is, it's seems the threads are running one after the other and not in concurrent.
Here is what I tried to do:
public class Copier {
private static final int POOL_SIZE = 2;
private static volatile Copier instance = null;
private static Semaphore semaphore;
private Copier() {
}
public static Copier getInstance() {
if (instance == null) {
synchronized (Copier.class) {
if (instance == null) {
instance = new Copier();
semaphore = new Semaphore(POOL_SIZE);
}
}
}
return instance;
}
public void fileTransfer(CopyThread copyThread) {
try {
semaphore.acquire();
System.out.println("Running thread...");
copyThread.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
semaphore.release();
System.out.println("Thread released..");
}
}
}
This is my Main
class:
public class Driver {
public static void main(String[] args) {
Copier copier = Copier.getInstance();
CopyThread copyThread1 = new CopyThread();
CopyThread copyThread2 = new CopyThread();
copier.fileTransfer(copyThread1);
copier.fileTransfer(copyThread2);
}
}
When running it - you can see by the output the threads running one after the other, while my purpose is to have up to 2 concurrent threads. What did I do wrong?
Running thread...
3.998784MB were transferred in 5.902514932 seconds
Thread released..
Running thread...
4.062673MB were transferred in 7.199550077 seconds
Thread released..
A semaphore might allow several threads/processes to access a resource, a mutex allows only ONE concurrent access to a resource. As stated here you would need to create a named semaphore to make cross-process-synchronisation possible.
A semaphore is a programming construct that helps us achieve concurrency, by implementing both synchronization and mutual exclusion. Semaphores are of two types, Binary and Counting. A semaphore has two parts : a counter, and a list of tasks waiting to access a particular resource.
Attempting to decrement the count past 0 causes the thread that is calling to wait for another thread to unlock the semaphore. Any thread can increment the count to unlock the semaphore (this is also called posting the semaphore). Posting a semaphore might wake up a waiting thread if there is one present.
The program uses a semaphore to control access to the count variable, which is a static variable within the Shared class.
Semaphores are thread safe as explained in the javadoc: Memory consistency effects: Actions in a thread prior to calling a "release" method such as release() happen-before actions following a successful "acquire" method such as acquire() in another thread. Most operations on the objects in the java. util.
You are supposed to call start()
instead of run()
otherwise it won't start your threads such that the transfer will be done sequentially which is actually the root cause of your current issue.
Anyway, for me your code should be rewritten as the class Copier
should not even start() the threads as it is not its duty.
fileTransfer()
public void fileTransfer() {
try {
semaphore.acquire();
System.out.println("Running transfer...");
// Code that performs the transfer
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
System.out.println("Thread released..");
}
}
run()
of CopyThread
properly@Override
public void run() {
// Here I call fileTransfer() on Copier instead of the other way around
Copier.getInstance().fileTransfer();
}
semaphore
non static and finalprivate final Semaphore semaphore;
private Copier() {
this.semaphore = new Semaphore(POOL_SIZE);
}
public class Copier {
...
public static Copier getInstance() {
return Holder.instance;
}
...
private static class Holder {
private static final Copier instance = new Copier();
}
}
main
methodpublic static void main(String[] args) throws Exception {
CopyThread copyThread1 = new CopyThread();
CopyThread copyThread2 = new CopyThread();
copyThread1.start();
copyThread2.start();
}
Output:
Running transfer...
Running transfer...
Thread released..
Thread released..
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With