I am currently trying to understand semaphores during parallel processing. I have instantiated a semaphore of 3 permits, and have a list of strings with five values, using executor service, I have created five threads using callable interface.
Now as per my understanding it should allow processing of three threads at the same time and once any one thread has completed the process, the next thread would acquire a lock and process it.
I have the sample snippet below and output I got after execution which shows available permit as 2 at the end. It takes on the values 0, 1, 0, 1, 2 during execution.
Provided the below the code snippet and output, I still can not understand how this works by looking at the output. Can some explain what happens internally and why I am not getting number 3 in available Permits?
Also I suggest some APIs that use semaphores.
Code:
public class SemaphoreDemo {
Semaphore semaphore= new Semaphore(3);
public void doit() {
List<String> ll =List.of("1","2","3","4","5");
List<Callable<String>> parallelprocess= new ArrayList<Callable<String>>(ll.size());
for(String data:ll) {
parallelprocess.add(()-> {
semaphore.acquire();
String res= data+Thread.currentThread().getName();
Thread.sleep(1000);
System.out.println(res);
System.out.println(semaphore.availablePermits());
semaphore.release();
return res;
});
}
ExecutorService executor=Executors.newFixedThreadPool(parallelprocess.size());
try {
List<Future<String>> reponse=executor.invokeAll(parallelprocess);
for(Future<String> future:reponse) {
try {
System.out.println(future.get().toString());
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
executor.shutdown();
}
public static void main(String[] args) {
SemaphoreDemo ss=new SemaphoreDemo();
ss.doit();
}
}
output:
3pool-1-thread-3
0
2pool-1-thread-2
1
1pool-1-thread-1
0
4pool-1-thread-4
1
5pool-1-thread-5
2
1pool-1-thread-1
2pool-1-thread-2
3pool-1-thread-3
4pool-1-thread-4
5pool-1-thread-5
I think the output is as expected (I mean, with multithreading the result is non-deterministic but the output you presented is one of the possible outcomes).
First, multiple threads are created and start executing at the same time. 1-3 threads execute semaphore.acquire(); before the first thread (first in time, can be any element of the array of threads) calls semaphore.availablePermits(). At that time it reads the actual number of available permits. Since Thread.sleep(1000); and System.out.println(res); take very long time, the chance that this happens before any of the other threads is activated, is extremely low. Therefore the first thread ("3" in this case) gets the value 0, and prints it. Then releases a permit.
After thread "3" has released the permit, thread "2" was resumed, it asks the number of permits, which is one because e.g. thread "4" did not have enough time to call semaphore.availablePermits(). Thread "3" prints this value.
Then "4" is resumed, takes a permit but before it gets to printing, "1" is activated, asks the number of permits, which is 0 again, and prints it.
Then "4" is resumed again, asks the number of permits, prints 1 as "3", "2" and "1" have already released theirs.
Then "5" is resumed, and since it is the only one holding a permit, it prints 2.
All of these could have happened in a different ordering causing a different order in which threads print their output and different permit numbers.
However, printing a permit number of 3 is never possible because the total number of permits is 3 and semaphore.availablePermits() is always called before semaphore.release(), therefore the last thread asking this is itself holding a permit while asking, and 3 - 1 = 2.
I find your last question, "Also I suggest some APIs that use semaphores." too broad. The functions you used are part of the API, and for what you use them is quite diverse, almost like what can you do with a floating point number.
Related
I'm working on a multithread application for an exercise used to simulate a warehouse (similar to the producer consumer problem) however I'm running into some trouble with the program where increasing the number of consumer threads makes the program behave in unexpected ways.
The code:
I'm creating a producer thread called buyer which has as a goal to order precisely 10 orders from the warehouse each. To do this they have a shared object called warehouse on which a buyer can place an order, the order is then stored in a buffer in the shared object. After this the buyer sleeps for some time until it either tries again or all packs have been bought. The code to do this looks like this:
public void run() {
//Run until the thread has bought 10 packages, this ensures the thread
//will eventually stop execution automatically.
while(this.packsBought < 10) {
try {
//Sleep for a random amount of time between 1 and 50
//milliseconds.
Thread.sleep(this.rand.nextInt(49) + 1);
//Catch any interruptExceptions.
} catch (InterruptedException ex) {
//There is no problem if this exception is thrown, the thread
//will just make an order earlier than planned. that being said
//there should be no manner in which this exception is thrown.
}
//Create a new order.
Order order = new Order(this.rand.nextInt(3)+ 1,
this,
this.isPrime);
//Set the time at which the order was placed as now.
order.setOrderTime(System.currentTimeMillis());
//place the newly created order in the warehouse.
this.warehouse.placeOrder(order);
}
//Notify the thread has finished execution.
System.out.println("Thread: " + super.getName() + " has finished.");
}
As you can see the function placeOrder(Order order); is used to place an order at the warehouse. this function is responsible for placing the order in the queue based on some logic related to prime status. The function looks like this:
public void placeOrder(Order order) {
try{
//halt untill there are enough packs to handle an order.
this.notFullBuffer.acquire();
//Lock to signify the start of the critical section.
this.mutexBuffer.lock();
//Insert the order in the buffer depending on prime status.
if (order.isPrime()) {
//prime order, insert behind all prime orders in buffer.
//Enumerate all non prime orders in the list.
for (int i = inPrime; i < sizeOrderList - 1; i++) {
//Move the non prime order back 1 position in the list.
buffer[i + 1] = buffer[i];
}
// Insert the prime order.
buffer[inPrime++] = order;
} else {
//No prime order, insert behind all orders in buffer.
buffer[inPrime + inNormal++] = order;
}
//Notify the DispatchWorkers that a new order has been placed.
this.notEmptyBuffer.release();
//Catch any InterruptException that might occure.
} catch(InterruptedException e){
//Even though this isn't expected behavior, there is no reason to
//notify the user of this event or to preform any other action as
//the thread will just return to the queue before placing another
//error if it is still required to do so.
} finally {
//Unlock and finalize the critical section.
mutexBuffer.unlock();
}
}
The orders are consumed by workers which act as the consumer thread. The thread itself contains very simple code looping until all orders have been processed. In this loop a different function handleOrder(); is called on the same warehouse object which handles a single order from the buffer. It does so with the following code:
public void handleOrder(){
//Create a variable to store the order being handled.
Order toHandle = null;
try{
//wait until there is an order to handle.
this.notEmptyBuffer.acquire();
//Lock to signify the start of the critical section.
this.mutexBuffer.lock();
//obtain the first order to handle as the first element of the buffer
toHandle = buffer[0];
//move all buffer elementst back by 1 position.
for(int i = 1; i < sizeOrderList; i++){
buffer[i - 1] = buffer[i];
}
//set the last element in the buffer to null
buffer[sizeOrderList - 1] = null;
//We have obtained an order from the buffer and now we can handle it.
if(toHandle != null) {
int nPacks = toHandle.getnPacks();
//wait until the appropriate resources are available.
this.hasBoxes.acquire(nPacks);
this.hasTape.acquire(nPacks * 50);
//Now we can handle the order (Simulated by sleeping. Although
//in real live Amazon workers also have about 5ms of time per
//package).
Thread.sleep(5 * nPacks);
//Calculate the total time this order took.
long time = System.currentTimeMillis() -
toHandle.getOrderTime();
//Update the total waiting time for the buyer.
toHandle.getBuyer().setWaitingTime(time +
toHandle.getBuyer().getWaitingTime());
//Check if the order to handle is prime or not.
if(toHandle.isPrime()) {
//Decrement the position of which prime orders are
//inserted into the buffer.
inPrime--;
} else {
//Decrement the position of which normal orders are
//inserted into the buffer.
inNormal--;
}
//Print a message informing the user a new order was completed.
System.out.println("An order has been completed for: "
+ toHandle.getBuyer().getName());
//Notify the buyer he has sucsessfully ordered a new package.
toHandle.getBuyer().setPacksBought(
toHandle.getBuyer().getPacksBought() + 1);
}else {
//Notify the user there was a critical error obtaining the
//error to handle. (There shouldn't exist a case where this
//should happen but you never know.)
System.err.println("Something went wrong obtaining an order.");
}
//Notify the buyers that a new spot has been opened in the buffer.
this.notFullBuffer.release();
//Catch any interrupt exceptions.
} catch(InterruptedException e){
//This is expected behavior as it allows us to force the thread to
//revaluate it's main running loop when notifying it to finish
//execution.
} finally {
//Check if the current thread is locking the buffer lock. This is
//done as in the case of an interrupt we don't want to execute this
//code if the thread interrupted doesn't hold the lock as that
//would result in an exception we don't want.
if (mutexBuffer.isHeldByCurrentThread())
//Unlock the buffer lock.
mutexBuffer.unlock();
}
}
The problem:
To verify the functionallity of the program I use the output from the statement:
System.out.println("An order has been completed for: "
+ toHandle.getBuyer().getName());
from the handleOrder(); function. I place the whole output in a text file, remove all the lines which aren't added by this println(); statement and count the number of lines to know how many orders have been handled. I expect this value to be equal to the amount of threads times 10, however this is often not the case. Running tests I've noticed sometimes it does work and there are no problems but sometimes one or more buyer threads take more orders than they should. with 5 buyer threads there should be 50 outputs but I get anywhere from 50 to 60 lines (orders places).
Turning the amount of threads up to 30 increases the problem and now I can expect an increase of up to 50% more orders with some threads placing up to 30 orders.
Doing some research this is called a data-race and is caused by 2 threads accessing the same data at the same time while 1 of them writes to the data. This basically changes the data such that the other thread isn't working with the same data it expects to be working with.
My attempt:
I firmly believe ReentrantLocks are designed to handle situations like this as they should stop any thread from entering a section of code if another thread hasn't left it. Both the placeOrder(Order order); and handleOrder(); function make use of this mechanic. I'm therefor assuming I didn't implement this correctly. Here is a version of the project which is compileable and executable from a single file called Test.java. Would anyone be able to take a look at that or the code explained above and tell me what I'm doing wrong?
EDIT
I noticed there was a way a buyer could place more than 10 orders so I changed the code to:
/*
* The run method which is ran once the thread is started.
*/
public void run() {
//Run until the thread has bought 10 packages, this ensures the thread
//will eventually stop execution automatically.
for(packsBought = 0; packsBought < 10; packsBought++)
{
try {
//Sleep for a random amount of time between 1 and 50
//milliseconds.
Thread.sleep(this.rand.nextInt(49) + 1);
//Catch any interruptExceptions.
} catch (InterruptedException ex) {
//There is no problem if this exception is thrown, the thread
//will just make an order earlier than planned. that being said
//there should be no manner in which this exception is thrown.
}
//Create a new order.
Order order = new Order(this.rand.nextInt(3)+ 1,
this,
this.isPrime);
//Set the time at which the order was placed as now.
order.setOrderTime(System.currentTimeMillis());
//place the newly created order in the warehouse.
this.warehouse.placeOrder(order);
}
//Notify the thread has finished execution.
System.out.println("Thread: " + super.getName() + " has finished.");
}
in the buyers run(); function yet I'm still getting some threads which place over 10 orders. I also removed the update of the amount of packs bought in the handleOrder(); function as that is now unnecessary. here is an updated version of Test.java (where all classes are together for easy execution) There seems to be a different problem here.
There are some concurrency issues with the code, but the main bug is not related to them: it's in the block starting in line 512 on placeOrder
//Enumerate all non prime orders in the list.
for (int i = inPrime; i < sizeOrderList - 1; i++) {
//Move the non prime order back 1 position in the list.
buffer[i + 1] = buffer[i];
}
when there is only one normal order in the buffer, then inPrime value is 0, inNormal is 1, buffer[0] is the normal order and the rest of the buffer is null.
The code to move non primer orders, starts in index 0, and then does:
buffer[1] = buffer[0] //normal order in 0 get copied to 1
buffer[2] = buffer[1] //now its in 1, so it gets copied to 2
buffer[3] = buffer[2] //now its in 2 too, so it gets copied to 3
....
so it moves the normal order to buffer[1] but then it copies the contents filling all the buffer with that order.
To solve it you should copy the array in reverse order:
//Enumerate all non prime orders in the list.
for (int i = (sizeOrderList-1); i > inPrime; i--) {
//Move the non prime order back 1 position in the list.
buffer[i] = buffer[i-1];
}
As for the concurrency issues:
If you check a field on a thread, updated by another thread you should declare it as volatile. Thats the case of the run field in DispatcherWorker and ResourceSupplier. See: https://stackoverflow.com/a/8063587/11751648
You start interrupting the dispatcher threads (line 183) while they are still processing packages. So if they are stopped at 573, 574 or 579, they will throw an InterruptedException and not finish the processing (hence in the last code not always all packages are delivered). You could avoid this by checking that the buffer is empty before start interrupting dispatcher threads, calling warehouse.notFullBuffer.acquire(warehouse.sizeOrderList); on 175
When catching InterruptedException you should always call Thread.currentThread().interrupt(); the preserve the interrupted status of the Thread. See: https://stackoverflow.com/a/3976377/11751648
I believe you may be chasing ghosts. I'm not entirely sure why you're seeing more outputs than you're expecting, but the number of orders placed appears to be in order. Allow me to clarify:
I've added a Map<String,Integer> to the Warehouse class to map how many orders each thread places:
private Map<String,Integer> ordersPlaced = new TreeMap<>();
// Code omitted for brevity
public void placeOrder(Order order)
{
try
{
//halt untill there are enough packs to handle an order.
this.notFullBuffer.acquire();
//Lock to signify the start of the critical section.
this.mutexBuffer.lock();
ordersPlaced.merge(Thread.currentThread().getName(), 1, Integer::sum);
// Rest of method
}
I then added a for-loop to the main method to execute the code 100 times, and added the following code to the end of each iteration:
warehouse.ordersPlaced.forEach((thread, orders) -> System.out.printf(" %s - %d%n", thread, orders));
I placed a breakpoint inside the lambda expression, with condition orders != 10. This condition never triggered in the 100+ runs I executed. As far as I can tell, your code is working as intended. I've increased both nWorkers and nBuyers to 100 just to be sure.
I believe you're using ReentrantLock correctly, and I agree that it is probably the best choice for your use case.
referring at your code on pastebin
THE GENERIC PROBLEM:
In the function public void handleOrder() he sleep (line 582) Thread.sleep(5 * nPacks); is inside the lock(): unlock(): block.
With this position of sleep, it has no sense to have many DispatchWorker because n-1 will wait at line 559 this.mutexBuffer.lock() while one is sleeping at line 582.
THE BUG:
The bug is in line 173. You should remove it.
In your main() you join all buyers and this is correct. Then you try to stop the workers. The workers at this time are already running to complete orders that will be completed seconds after. You should only set worker.runThread(false); and then join the thead (possibly in two separate loops). This solution really waits for workers to complete orders. Interrupting the thread that is sleeping at line 582 will raise an InterruptedException and the following lines are skipped, in particular line 596 or 600 that update inPrime and in Normal counters generating unpredictable behaviours.
moving line 582 after line 633 and removing line 173 will solve the problem
HOW TO TEST:
My suggestion is to introduce a counter of all Packs boxes generated by supplier and a counter of all boxes ordered and finally check if generated boxes are equals at ordered plus that left in the whorehouse.
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Processor implements Runnable {
private CountDownLatch latch;
public Processor(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
System.out.println("Started.");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();
}
}
// -----------------------------------------------------
public class App {
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(5); // coundown from 5 to 0
ExecutorService executor = Executors.newFixedThreadPool(2); // 2 Threads in pool
for(int i=0; i < 10; i++) {
executor.submit(new Processor(latch)); // ref to latch. each time call new Processes latch will count down by 1
}
try {
latch.await(); // wait until latch counted down to 0
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Completed.");
}
}
Output:
Started
Started
Started
Started
Started
Started
Started
Completed`
Started
Started
Started
In the above code "Completed" should be printed after 6 times "Started" as latch count downs to 5 - 0, why it is always 7th or 8th time? Have i understood wrong?
Your thread pool has size 2 and your Processor threads take 3 seconds to execute.
First two Processors threads are started, the both print Started and they finish 3 seconds later.
Then the next two are started and again they both print Started and finish 3 second later.
Then another two (5th and 6th) are started, print Started and 3 seconds later when one of them (or both) finishes. At this point there are multiple things that are going to happen at roughly the same time (so the order is kind of random):
The main thread resumes and prints Completed
7th Processor thread is started and prints Started
8th Processor thread is started and prints Started
Therefore, Completed is always going to be preceded by 6, 7 or 8 Started print outs.
So, CountDownLatch does not guarantee that it will resume the parent thread (here I mean the thread from which you have called latch.await();) execution as soon as the Count Down goes to 0. So, what happens when Count Down latch countdown to 0 that means now parent Thread can resume its work and that does not mean it will get the get the CPU then and there. So, it can resume that does not mean CPU schedule the parent thread as soon as the countdown to 0. If there are other threads then is there is a possibility that those can execute before the parent thread. In your case, it ensures that it will not execute before the 5 time printing Started but it does ensure that it will be exactly after printing 5 times Started. You may also observe at a certain execution of your code Completed is printing at end of all Started printing.
I have threads which are given random number (1 to n) and are instructed to print them in sorted order. I used semaphore such that I acquire the number of permits = random number and release one permit more than what was acquired.
acquired = random number; released = 1+random number
Initial permit count for semaphore is 1. So thread with random number 1 should get permit and then 2 and so on.
This is supported as per the documentation given below
There is no requirement that a thread that releases a permit must have acquired that permit by calling acquire().
The problem is my program gets stuck after 1 for n>2.
My program is given below:
import java.util.concurrent.Semaphore;
public class MultiThreading {
public static void main(String[] args) {
Semaphore sem = new Semaphore(1,false);
for(int i=5;i>=1;i--)
new MyThread(i, sem);
}
}
class MyThread implements Runnable {
int var;Semaphore sem;
public MyThread(int a, Semaphore s) {
var =a;sem=s;
new Thread(this).start();
}
#Override
public void run() {
System.out.println("Acquiring lock -- "+var);
try {
sem.acquire(var);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(var);
System.out.println("Releasing lock -- "+var);
sem.release(var+1);
}
}
Output is :
Acquiring lock -- 4
Acquiring lock -- 5
Acquiring lock -- 3
Acquiring lock -- 2
Acquiring lock -- 1
1
Releasing lock -- 1
While If I modify my code with tryAcquire, it runs perfectly well.
Below is new run implementation
#Override
public void run() {
boolean acquired = false;
while(!acquired) {
acquired = sem.tryAcquire(var);
}
System.out.println(var);
sem.release(var+1);
}
Can someone please explain the semaphore's permit acquire mechanism when mulitple threads are waiting with different permit request??
It's a clever strategy, but you're misunderstanding how Sempahore hands out permits. If you run your code enough times you'll actually see it reach step two:
Acquiring lock -- 5
Acquiring lock -- 1
1
Releasing lock -- 1
Acquiring lock -- 3
Acquiring lock -- 2
2
Acquiring lock -- 4
Releasing lock -- 2
If you keep on re-running it enough times you'd actually see it successfully finish. This happens because of how Semaphore hands out permits. You're assuming Semaphore will try to accommodate an acquire() call as soon as it has enough permits to do so. If we look carefully at the documentation for Semaphore.aquire(int) we'll see that is not the case (emphasis mine):
If insufficient permits are available then the current thread becomes disabled for thread scheduling purposes and lies dormant until ... some other thread invokes one of the release methods for this semaphore, the current thread is next to be assigned permits and the number of available permits satisfies this request.
In other words Semaphore keeps a queue of pending acquire request and, upon each call to .release(), only checks the head of the queue. In particular if you enable fair queuing (set the second constructor argument to true) you'll see even step one doesn't occur, because step 5 is (usually) the first in the queue and even new acquire() calls that could be fulfilled will be queued up behind the other pending calls.
In short this means you cannot rely on .acquire() to return as soon as possible, as your code assumes.
By using .tryAcquire() in a loop instead you avoid making any blocking calls (and therefore put a lot more load on your Semaphore) and as soon as the necessary number of permits becomes available a tryAcquire() call will successfully obtain them. This works but is wasteful.
Picture a wait-list at a restaurant. Using .aquire() is like putting your name on the list and waiting to be called. It may not be perfectly efficient, but they'll get to you in a (reasonably) fair amount of time. Imagine instead if everyone just shouted at the host "Do you have a table for n yet?" as often as they could - that's your tryAquire() loop. It may still work out (as it does in your example) but it's certainly not the right way to go about it.
So what should you do instead? There's a number of possibly useful tools in java.util.concurrent, and which is best somewhat depends on what exactly you're trying to do. Seeing as you're effectively having each thread start the next one I might use a BlockingQueue as the synchronization aid, pushing the next step into the queue each time. Each thread would then poll the queue, and if it's not the activated thread's turn replace the value and wait again.
Here's an example:
public class MultiThreading {
public static void main(String[] args) throws Exception{
// Use fair queuing to prevent an out-of-order task
// from jumping to the head of the line again
// try setting this to false - you'll see far more re-queuing calls
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(1, true);
for (int i = 5; i >= 1; i--) {
Thread.sleep(100); // not necessary, just helps demonstrate the queuing behavior
new MyThread(i, queue).start();
}
queue.add(1); // work starts now
}
static class MyThread extends Thread {
int var;
BlockingQueue<Integer> queue;
public MyThread(int var, BlockingQueue<Integer> queue) {
this.var = var;
this.queue = queue;
}
#Override
public void run() {
System.out.println("Task " + var + " is now pending...");
try {
while (true) {
int task = queue.take();
if (task != var) {
System.out.println(
"Task " + var + " got task " + task + " instead - re-queuing");
queue.add(task);
} else {
break;
}
}
} catch (InterruptedException e) {
// If a thread is interrupted, re-mark the thread interrupted and terminate
Thread.currentThread().interrupt();
return;
}
System.out.println("Finished task " + var);
System.out.println("Registering task " + (var + 1) + " to run next");
queue.add(var + 1);
}
}
}
This prints the following and terminates successfully:
Task 5 is now pending...
Task 4 is now pending...
Task 3 is now pending...
Task 2 is now pending...
Task 1 is now pending...
Task 5 got task 1 instead - re-queuing
Task 4 got task 1 instead - re-queuing
Task 3 got task 1 instead - re-queuing
Task 2 got task 1 instead - re-queuing
Finished task 1
Registering task 2 to run next
Task 5 got task 2 instead - re-queuing
Task 4 got task 2 instead - re-queuing
Task 3 got task 2 instead - re-queuing
Finished task 2
Registering task 3 to run next
Task 5 got task 3 instead - re-queuing
Task 4 got task 3 instead - re-queuing
Finished task 3
Registering task 4 to run next
Task 5 got task 4 instead - re-queuing
Finished task 4
Registering task 5 to run next
Finished task 5
Registering task 6 to run next
The Javadoc for Semaphore.acquire(int) says:
If insufficient permits are available then the current thread becomes
disabled for thread scheduling purposes and lies dormant until one of
two things happens:
Some other thread invokes one of the release methods for this semaphore,
the current thread is next to be assigned permits and the number of
available permits satisfies this request [or the thread is interrupted].
The thread that is "next to be assigned" is probably thread 4 in your example. It is waiting until there are 4 permits available. However, thread 1, which gets a permit upon calling acquire(), only releases 2 permits, which is not enough to unblock thread 4. Meanwhile, thread 2, which is the only thread for which there are sufficient permits, is not the next to be assigned, so it doesn't get the permits.
Your modified code runs fine because the threads don't block when they try to get a semaphore; they just try again, going to the back of the line. Eventually thread 2 reaches the front of the line and is thus next to be assigned, and so gets its permits.
I am preparing for interviews and just want to prepare some basic threading examples and structures so that I can use them during my white board coding if I have to.
I was reading about CyclicBarrier and was just trying my hands at it, so I wrote a very simple code:
import java.util.concurrent.CyclicBarrier;
public class Threads
{
/**
* #param args
*/
public static void main(String[] args)
{
// ******************************************************************
// Using CyclicBarrier to make all threads wait at a point until all
// threads reach there
// ******************************************************************
barrier = new CyclicBarrier(N);
for (int i = 0; i < N; ++i)
{
new Thread(new CyclicBarrierWorker()).start();
}
// ******************************************************************
}
static class CyclicBarrierWorker implements Runnable
{
public void run()
{
try
{
long id = Thread.currentThread().getId();
System.out.println("I am thread " + id + " and I am waiting for my friends to arrive");
// Do Something in the Thread
Thread.sleep(1000*(int)(4*Math.random()*10));
// Now Wait till all the thread reaches this point
barrier.await();
}
catch (Exception e)
{
e.printStackTrace();
}
//Now do whatever else after all threads are released
long id1 = Thread.currentThread().getId();
System.out.println("Thread:"+id1+" We all got released ..hurray!!");
System.out.println("We all got released ..hurray!!");
}
}
final static int N = 4;
static CyclicBarrier barrier = null;
}
You can copy paste it as is and run in your compiler.
What I want to verify is that indeed all threads wait at this point in code:
barrier.await();
I put some wait and was hoping that I would see 4 statements appear one after other in a sequential fashion on the console, followed by 'outburst' of "released..hurray" statement. But I am seeing outburst of all the statements together no matter what I select as the sleep.
Am I missing something here ?
Thanks
P.S: Is there an online editor like http://codepad.org/F01xIhLl where I can just put Java code and hit a button to run a throw away code ? . I found some which require some configuration before I can run any code.
The code looks fine, but it might be more enlightening to write to System.out before the sleep. Consider this in run():
long id = Thread.currentThread().getId();
System.out.println("I am thread " + id + " and I am waiting for my friends to arrive");
// Do Something in the Thread
Thread.sleep(1000*8);
On my machine, I still see a burst, but it is clear that the threads are blocked on the barrier.
if you want to avoid the first burst use a random in the sleep
Thread.sleep(1000*(int)(8*Math.rand()));
I put some wait and was hoping that I
would see 4 statements appear one
after other in a sequential fashion on
the console, followed by 'outburst' of
"released..hurray" statement. But I am
seeing outburst of all the statements
together no matter what I select as
the sleep.
The behavior I'm observing is that all the threads created, sleep for approximately the same amount of time. Remember that other threads can perform their work in the interim, and will therefore get scheduled; since all threads created sleep for the same amount of time, there is very little difference between the instants of time when the System.out.println calls are invoked.
Edit: The other answer of sleeping of a random amount of time will aid in understanding the concept of a barrier better, for it would guarantee (to some extent) the possibility of multiple threads arriving at the barrier at different instants of time.
Can the semaphore be lower than 0? I mean, say I have a semaphore with N=3 and I call "down" 4 times, then N will remain 0 but one process will be blocked?
And same the other way, if in the beginning I call up, can N be higher than 3? Because as I see it, if N can be higher than 3 if in the beginning I call up couple of times, then later on I could call down more times than I can, thus putting more processes in the critical section then the semaphore allows me.
If someone would clarify it a bit for me I will much appreciate.
Greg
(Using the terminology from java.util.concurrent.Semaphore given the Java tag. Some of these details are implementation-specific. I suspect your "down" is the Java semaphore's acquire() method, and your "up" is release().)
Yes, your last call to acquire() will block until another thread calls release() or your thread is interrupted.
Yes, you can call release() more times, then down more times - at least with java.util.concurrent.Semaphore.
Some other implementations of a semaphore may have an idea of a "maximum" number of permits, and a call to release beyond that maximum would fail. The Java Semaphore class allows a reverse situation, where a semaphore can start off with a negative number of permits, and all acquire() calls will fail until there have been enough release() calls. Once the number of permits has become non-negative, it will never become negative again.
Calling down when it's 0 should not work. Calling up when it's 3 does work. (I am thinking of Java).
Let me add some more. Many people think of locks like (binary) semaphores (ie - N = 1, so the value of the semaphore is either 0 (held) or 1 (not held)). But this is not quite right. A lock has a notion of "ownership" so it may be "reentrant". That means that a thread that holds a lock, is allowed to call lock() again (effectively moving the count from 0 to -1), because the thread already holds the lock and is allowed to "reenter" it. Locks can also be non reentrant. A lock holder is expected to call unlock() the same number of times as lock().
Semaphores have no notion of ownership, so they cannot be reentrant, although as many permits as are available may be acquired. That means a thread needs to block when it encounters a value of 0, until someone increments the semaphore.
Also, in what I have seen (which is Java), you can increment the semaphore greater than N, and that also sort of has to do with ownership: a Semaphore has no notion of ownership so anybody can give it more permits. Unlike a thread, where whenever a thread calls unlock() without holding a lock, that is an error. (In java it will throw an exception).
Hope this way of thinking about it helps.
Hi Greg consider following example :
public static void main(String [] args) throws InterruptedException {
Semaphore available = new Semaphore(1, true);
available.acquire();
System.out.println("Acquire : " +available.availablePermits());
available.release();
System.out.println("Released : " +available.availablePermits());
available.release();
System.out.println("Released : " +available.availablePermits());
available.release();
System.out.println("Released : " +available.availablePermits());
available.release();
System.out.println("Released : " +available.availablePermits());
available.acquire();
System.out.println("Acquire : " +available.availablePermits());
available.acquire();
System.out.println("Acquire : " +available.availablePermits());
available.acquire();
System.out.println("Acquire : " +available.availablePermits());
available.acquire();
System.out.println("Acquire : " +available.availablePermits());
available.acquire();
System.out.println("Acquire : " +available.availablePermits());
}
If you see the output u will get following :
Acquire : 0
Released : 1
Released : 2
Released : 3
Released : 4
Acquire : 3
Acquire : 2
Acquire : 1
Acquire : 0
And wait is going on.
So basically permit will increase on every release and acquire will decrease it until 0.
Once it reached 0 it will wait until release is called on same object :)
Yes, a negative value means you have processes waiting for the semaphore to be released. A positive value means you can call acquire that many times before the semaphore blocks.
You could think of the value in this way: a positive number means there are that many resources available. A negative value means there are that many entities needing a resource when all resources are taken at the moment. When you acquire a resource you decrement the value, when you release it you increase the value. If the value is still >= 0 after the decrement you get the resource, otherwise your entity is put into a queue.
A nice explanation of semaphores in Wikipedia:
http://en.wikipedia.org/wiki/Semaphore_(programming)
Just see N as the counter that counts your limited resource. Since you can not have a negative number of resources, N remains >= 0. If the number of your available resources changes, the maximum N has to be changed, too. I wouln't consider it good style to increment n without decrementing it first in any other case.
Using java.util.concurrent.Semaphore with methods acquire() and release(), I think permits will always be >=0. Let's say you want to synchronize threads so that only 1 thread can be inside for loop. If sem is type of Semaphore that has initial value 1, this will not work for more than 2 threads.
while(true){
sem.wait(); // wait is acquire
for(int i=0; i<=5; i++){
try {
Thread.sleep(250);
}catch (InterruptedException e) {}
System.out.println("Thread "+ threadname+ " " + i);
}
sem.signal(); // signal is release }
However, you can implement the Semaphore class from java and make your own class that allows this.
package yourpackage;
import java.util.concurrent.Semaphore;
public class SemaphoreLayer {
public Semaphore s=null;
public String name;
private int val;
public SemaphoreLayer(int i){
s=new Semaphore(i); val=i;
}
public void wait(){
try {
val--;
s.acquire();
} catch (InterruptedException e) {
System.out.println("Error signal semaphorelayer");
}}
public void signal(){
if(val<0){val++;}{
s.release();
val++;
}
}
}
Now val can be negative. However, I am not sure that this is completely safe, because if we have signal from one thread and wait from the other and they try val++ and val-- this can be bad. (chances for this are very small but stil they exist, so if you are coding and you have to be 100% no error, I don't recommend using this code )
In conclusion this is why it is better to use concept of monitors in java and key word synchronized.