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.
Related
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.
Talk is cheap. Show the code.
MyCyclicBarrier.java
public class MyCyclicBarrier extends Thread{
private CyclicBarrier cyclicBarrier;
public MyCyclicBarrier(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
#Override
public void run() {
System.out.println("Thread start." + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(2); //biz code
System.out.println("Thread "+Thread.currentThread().getName()+" is waiting for the other Threads."+
"\n\t\t\t\tIt's parties is "+cyclicBarrier.getParties()+
"\n\t\t\t\tWaiting for "+cyclicBarrier.getNumberWaiting()+" Threads");
cyclicBarrier.await(3,TimeUnit.SECONDS);
} catch (InterruptedException | BrokenBarrierException | TimeoutException e) {
e.printStackTrace();
}
System.out.println("Thread end."+Thread.currentThread().getName());
}
}
TestCyclicbarrier.java
public class TestCyclicbarrier1 {
public static void main(String[] args) {
int length = 5;
long start = System.currentTimeMillis();
CyclicBarrier cyclicBarrierWithRunnable = new CyclicBarrier(length, () -> {
System.out.println("the final reach Thread is " + Thread.currentThread().getName());
long end = System.currentTimeMillis();
System.out.println("cost totally :" + (end - start) / 1000 + "s");
});
for (int i = 0; i < length; i++) {
if (i != 4) {
new MyCyclicBarrier(cyclicBarrierWithRunnable).start();
} else {
try {
TimeUnit.SECONDS.sleep(2);
new MyCyclicBarrier(cyclicBarrierWithRunnable).start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Output:
Thread start.Thread-1
Thread start.Thread-0
Thread start.Thread-2
Thread start.Thread-3
Thread Thread-0 is waiting for the other Threads.
It's parties is 5
Waiting for 0 Threads
Thread Thread-3 is waiting for the other Threads.
It's parties is 5
Waiting for 0 Threads
Thread start.Thread-4
Thread Thread-1 is waiting for the other Threads.
It's parties is 5
Waiting for 0 Threads
Thread Thread-2 is waiting for the other Threads.
It's parties is 5
Waiting for 1 Threads
Thread Thread-4 is waiting for the other Threads.
It's parties is 5
Waiting for 4 Threads
the final reach Thread is Thread-4
cost totally :4s
Thread end.Thread-4
Thread end.Thread-0
Thread end.Thread-3
Thread end.Thread-2
Thread end.Thread-1
I am searching for a long time on net. But no similar answer. Please help or try to give some ideas! And I just start to learn CyclicBarrier.
I wonder if I have misunderstood CyclicBarrier.await(int timeout,TimeUnit unit). Threads 0 through 3 have already reached the barrier point that cost 2s.In the same time the final Thread started after 2s of waiting.After 1 second number 0 to 3 Threads reach the specified timeout which number 4 thread still excuted its own code. Here is the question: Why did CyclicBarrier.await(int timeout, TimeUnit unit) didn't throw TimeOutException here?
Threads 0 through 3 have already reached the Barrier point that cost 2s.
This is correct.
In the same time the final Thread started after 2s of waiting.
Correct. Note, by the time this thread starts, other 4 threads are awaiting the CB (3 secs timeout i.e., we have 3 secs until a TimeoutException can occur).
But thread 4 sleeps for only 2 seconds in the run method (we still have only 1 sec until the TimeoutException).
When it comes to await, it is the last thread - so it doesn't have to wait anymore. Hence the barrier action gets run and others are unblocked - from javadoc,
If the current thread is the last thread to arrive, and a
non-null barrier action was supplied in the constructor, then the current thread runs the action before allowing the other threads to continue.
If you make sleep for four seconds before starting thread-4, you would get a TimeoutException.
try {
TimeUnit.SECONDS.sleep(4);
new MyCyclicBarrier(cyclicBarrierWithRunnable).start();
} catch (InterruptedException e) {
e.printStackTrace();
}
You seem to think that the timeout starts when the thread starts:
Threads 0 through 3 have already reached the Barrier point that cost 2s.
After 1 second number 0 to 3 Threads reach the specified timeout
This is wrong. When you call
cyclicBarrier.await(3,TimeUnit.SECONDS);
it doesn't matter how long it took the threads to reach that point - the timeout is 3 seconds from the moment the method cyclicBarrier.await() is called.
Since thread 4 has only an additional delay of 2 seconds it still arrives in time.
To clarify further this is what the timeline looks like:
t=0s
main() creates the CyclicBarrier and starts threads 0 to 3
the threads 0 to 3 start and call TimeUnit.SECONDS.sleep(2);
main calls TimeUnit.SECONDS.sleep(2);
t=2s
main() starts thread 4
the threads 0 to 3 awake, print out something and then call cyclicBarrier.await(3,TimeUnit.SECONDS); which means that they will be interrupted at t=5s (t=2s + 3s)
thread 4 stars and calls TimeUnit.SECONDS.sleep(2);
t=4s
thread 4 awakes, prints out something and then calls cyclicBarrier.await(3,TimeUnit.SECONDS);.
since now all threads are within cyclicBarrier.await(3,TimeUnit.SECONDS);, the condition for the CyclicBarrier is fulfilled and all threads continue
the timeout for thread 4 doesn't get used (because it is the last thread to reach the CyclicBarrier)
for threads 0 to 3 the timeout at t=5s is never reached
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 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.