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.
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.
I want to find out all the prime numbers from 0 to 1000000. For that I wrote this stupid method:
public static boolean isPrime(int n) {
for(int i = 2; i < n; i++) {
if (n % i == 0)
return false;
}
return true;
}
It's good for me and it doesn't need any edit. Than I wrote the following code:
private static ExecutorService executor = Executors.newFixedThreadPool(10);
private static AtomicInteger counter = new AtomicInteger(0);
private static AtomicInteger numbers = new AtomicInteger(0);
public static void main(String args[]) {
long start = System.currentTimeMillis();
while (numbers.get() < 1000000) {
final int number = numbers.getAndIncrement(); // (1) - fast
executor.submit(new Runnable() {
#Override
public void run() {
// int number = numbers.getAndIncrement(); // (2) - slow
if (Main.isPrime(number)) {
System.out.println("Ts: " + new Date().getTime() + " " + Thread.currentThread() + ": " + number + " is prime!");
counter.incrementAndGet();
}
}
});
}
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
System.out.println("Primes: " + counter);
System.out.println("Delay: " + (System.currentTimeMillis() - start));
} catch (Exception e) {
e.printStackTrace();
}
}
Please, pay attention to (1) and (2) marked rows. When (1) is enabled the program runs fast, but when (2) is enabled it works slower.
The output shows small portions with large delay
Ts: 1480489699692 Thread[pool-1-thread-9,5,main]: 350431 is prime!
Ts: 1480489699692 Thread[pool-1-thread-6,5,main]: 350411 is prime!
Ts: 1480489699692 Thread[pool-1-thread-4,5,main]: 350281 is prime!
Ts: 1480489699692 Thread[pool-1-thread-5,5,main]: 350257 is prime!
Ts: 1480489699693 Thread[pool-1-thread-7,5,main]: 350447 is prime!
Ts: 1480489711996 Thread[pool-1-thread-6,5,main]: 350503 is prime!
and threads get equal number value:
Ts: 1480489771083 Thread[pool-1-thread-8,5,main]: 384733 is prime!
Ts: 1480489712745 Thread[pool-1-thread-6,5,main]: 384733 is prime!
Please explain me why option (2) is more slowly and why threads get equal value for number despite AtomicInteger multithreading safe?
In the (2) case, up to 11 threads (the ten from the ExecutorService plus the main thread) are contending for access to the AtomicInteger, whereas in case (1) only the main thread accesses it. In fact, for case (1) you could use int instead of AtomicInteger.
The AtomicInteger class makes use of CAS registers. It does this by reading the value, doing the increment, and then swapping the value with the value in the register if it still has the same value that was originally read (compare and swap). If another thread has changed the value it retries by starting again : read - increment - compare-and-swap, until it is succesful.
The advantage is that this is lockless, and therefore potentially faster than using locks. But it performs poorly under heavy contention. More contention means more retries.
Edit
As #teppic points out, another problem makes case (2) slower than case (1). As the increment of numbers happens in the posted jobs, the loop condition remains true for much longer than needed. While all 10 threads of the executor are churning away to determine whether their given number is a prime, the main thread keeps posting new jobs to the executor. These new jobs don't get an opportunity to increment numbers until preceding jobs are done. So while they're on the queue numbers does not increase and the main thread can meanwhile complete one or more loops loop, posting new jobs. The end result is that many more jobs can be created and posted than the needed 1000000.
Your outer loop is:
while (numbers.get() < 1000000)
This allows you to continue submitting more Runnables than intended to the ExecutorService in the main thread.
You could try changing the loop to: for(int i=0; i < 1000000; i++)
(As others have mentioned you are obviously increasing the amount of contention, but I suspect the extra worker threads are a larger factor in the slowdown you are seeing.)
As for your second question, I'm pretty sure that it is against the contract of AtomicInteger for two child threads to see the same value of getAndIncrement. So something else must be going on which I am not seeing from your code sample. Might it be that you are seeing output from two separate runs of the program?
Explain me why option (2) is more slowly?
Simply because you do it inside run(). So multiple threads will try to do it at the same time hence there will be wait s and release s. Bowmore has given a low level explanation.
In (1) it is sequential. So there will be no such a scenario.
Why threads get equal value for number despite AtomicInteger
multithreading safe?
I don't see any possibility to happen this. If there's such a case it should happen from 0.
You miss two main points here: what AtomicInteger is for and how multithreading works in general.
Regarding why Option 2 is slower, #bowmore provided an excellent answer already.
Now regarding printing same number twice. AtomicInteger is like any other object. You launch your threads, and they check the value of this object. Since they compete with your main thread, that increases the counter, two child threads still may see same value. I would pass an int to each Runnable to avoid that.
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.
Why is i++ not atomic in Java?
To get a bit deeper in Java I tried to count how often the loop in threads are executed.
So I used a
private static int total = 0;
in the main class.
I have two threads.
Thread 1: Prints System.out.println("Hello from Thread 1!");
Thread 2: Prints System.out.println("Hello from Thread 2!");
And I count the lines printed by thread 1 and thread 2. But the lines of thread 1 + lines of thread 2 don't match the total number of lines printed out.
Here is my code:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Test {
private static int total = 0;
private static int countT1 = 0;
private static int countT2 = 0;
private boolean run = true;
public Test() {
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
newCachedThreadPool.execute(t1);
newCachedThreadPool.execute(t2);
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
run = false;
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println((countT1 + countT2 + " == " + total));
}
private Runnable t1 = new Runnable() {
#Override
public void run() {
while (run) {
total++;
countT1++;
System.out.println("Hello #" + countT1 + " from Thread 2! Total hello: " + total);
}
}
};
private Runnable t2 = new Runnable() {
#Override
public void run() {
while (run) {
total++;
countT2++;
System.out.println("Hello #" + countT2 + " from Thread 2! Total hello: " + total);
}
}
};
public static void main(String[] args) {
new Test();
}
}
i++ is probably not atomic in Java because atomicity is a special requirement which is not present in the majority of the uses of i++. That requirement has a significant overhead: there is a large cost in making an increment operation atomic; it involves synchronization at both the software and hardware levels that need not be present in an ordinary increment.
You could make the argument that i++ should have been designed and documented as specifically performing an atomic increment, so that a non-atomic increment is performed using i = i + 1. However, this would break the "cultural compatibility" between Java, and C and C++. As well, it would take away a convenient notation which programmers familiar with C-like languages take for granted, giving it a special meaning that applies only in limited circumstances.
Basic C or C++ code like for (i = 0; i < LIMIT; i++) would translate into Java as for (i = 0; i < LIMIT; i = i + 1); because it would be inappropriate to use the atomic i++. What's worse, programmers coming from C or other C-like languages to Java would use i++ anyway, resulting in unnecessary use of atomic instructions.
Even at the machine instruction set level, an increment type operation is usually not atomic for performance reasons. In x86, a special instruction "lock prefix" must be used to make the inc instruction atomic: for the same reasons as above. If inc were always atomic, it would never be used when a non-atomic inc is required; programmers and compilers would generate code that loads, adds 1 and stores, because it would be way faster.
In some instruction set architectures, there is no atomic inc or perhaps no inc at all; to do an atomic inc on MIPS, you have to write a software loop which uses the ll and sc: load-linked, and store-conditional. Load-linked reads the word, and store-conditional stores the new value if the word has not changed, or else it fails (which is detected and causes a re-try).
i++ involves two operations :
read the current value of i
increment the value and assign it to i
When two threads perform i++ on the same variable at the same time, they may both get the same current value of i, and then increment and set it to i+1, so you'll get a single incrementation instead of two.
Example :
int i = 5;
Thread 1 : i++;
// reads value 5
Thread 2 : i++;
// reads value 5
Thread 1 : // increments i to 6
Thread 2 : // increments i to 6
// i == 6 instead of 7
Java specification
The important thing is the JLS (Java Language Specification) rather than how various implementations of the JVM may or may not have implemented a certain feature of the language.
The JLS defines the ++ postfix operator in clause 15.14.2 which says i.a. "the value 1 is added to the value of the variable and the sum is stored back into the variable". Nowhere does it mention or hint at multithreading or atomicity.
For multithreading or atomicity, the JLS provides volatile and synchronized. Additionally, there are the Atomic… classes.
Why is i++ not atomic in Java?
Let's break the increment operation into multiple statements:
Thread 1 & 2 :
Fetch value of total from memory
Add 1 to the value
Write back to the memory
If there is no synchronization then let's say Thread one has read the value 3 and incremented it to 4, but has not written it back. At this point, the context switch happens. Thread two reads the value 3, increments it and the context switch happens. Though both threads have incremented the total value, it will still be 4 - race condition.
i++ is a statement which simply involves 3 operations:
Read current value
Write new value
Store new value
These three operations are not meant to be executed in a single step or in other words i++ is not a compound operation. As a result all sorts of things can go wrong when more than one threads are involved in a single but non-compound operation.
Consider the following scenario:
Time 1:
Thread A fetches i
Thread B fetches i
Time 2:
Thread A overwrites i with a new value say -foo-
Thread B overwrites i with a new value say -bar-
Thread B stores -bar- in i
// At this time thread B seems to be more 'active'. Not only does it overwrite
// its local copy of i but also makes it in time to store -bar- back to
// 'main' memory (i)
Time 3:
Thread A attempts to store -foo- in memory effectively overwriting the -bar-
value (in i) which was just stored by thread B in Time 2.
Thread B has nothing to do here. Its work was done by Time 2. However it was
all for nothing as -bar- was eventually overwritten by another thread.
And there you have it. A race condition.
That's why i++ is not atomic. If it was, none of this would have happened and each fetch-update-store would happen atomically. That's exactly what AtomicInteger is for and in your case it would probably fit right in.
P.S.
An excellent book covering all of those issues and then some is this:
Java Concurrency in Practice
In the JVM, an increment involves a read and a write, so it's not atomic.
If the operation i++ would be atomic you wouldn't have the chance to read the value from it. This is exactly what you want to do using i++ (instead of using ++i).
For example look at the following code:
public static void main(final String[] args) {
int i = 0;
System.out.println(i++);
}
In this case we expect the output to be: 0
(because we post increment, e.g. first read, then update)
This is one of the reasons the operation can't be atomic, because you need to read the value (and do something with it) and then update the value.
The other important reason is that doing something atomically usually takes more time because of locking. It would be silly to have all the operations on primitives take a little bit longer for the rare cases when people want to have atomic operations. That is why they've added AtomicInteger and other atomic classes to the language.
There are two steps:
fetch i from memory
set i+1 to i
so it's not atomic operation.
When thread1 executes i++, and thread2 executes i++, the final value of i may be i+1.
In JVM or any VM, the i++ is equivalent to the following:
int temp = i; // 1. read
i = temp + 1; // 2. increment the value then 3. write it back
that is why i++ is non-atomic.
Concurrency (the Thread class and such) is an added feature in v1.0 of Java. i++ was added in the beta before that, and as such is it still more than likely in its (more or less) original implementation.
It is up to the programmer to synchronize variables. Check out Oracle's tutorial on this.
Edit: To clarify, i++ is a well defined procedure that predates Java, and as such the designers of Java decided to keep the original functionality of that procedure.
The ++ operator was defined in B (1969) which predates java and threading by just a tad.
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.