I am doing a sample program with wait() and notify(), but when notify() is called, more than one thread is wakes up instead of one.
The code is:
public class MyQueue<T> {
Object[] entryArr;
private volatile int addIndex;
private volatile int pending = -1;
private final Object lock = new Object();
private volatile long notifiedThreadId;
private int capacity;
public MyQueue(int capacity) {
entryArr = new Object[capacity];
this.capacity = capacity;
}
public void add(T t) {
synchronized (lock) {
if (pending >= 0) {
try {
pending++;
lock.wait();
System.out.println(notifiedThreadId + ":" + Thread.currentThread().getId());
} catch (InterruptedException e) {
e.printStackTrace();
}
} else if (pending == -1) {
pending++;
}
}
if (addIndex == capacity) { // its ok to replace existing value
addIndex = 0;
}
try {
entryArr[addIndex] = t;
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("ARRAYException:" + Thread.currentThread().getId() + ":" + pending + ":" + addIndex);
e.printStackTrace();
}
addIndex++;
synchronized (lock) {
if (pending > 0) {
pending--;
notifiedThreadId = Thread.currentThread().getId();
lock.notify();
} else if (pending == 0) {
pending--;
}
}
}
}
public class TestMyQueue {
public static void main(String args[]) {
final MyQueue<String> queue = new MyQueue<>(2);
for (int i = 0; i < 200; i++) {
Runnable r = new Runnable() {
#Override
public void run() {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
queue.add(Thread.currentThread().getName() + ":" + i);
}
}
};
Thread t = new Thread(r);
t.start();
}
}
}
After some time, I see two threads being wake up by single thread. The output looks like:
91:114
114:124
124:198
198:106
106:202
202:121
121:40
40:42
42:83
83:81
81:17
17:189
189:73
73:66
66:95
95:199
199:68
68:201
201:70
70:110
110:204
204:171
171:87
87:64
64:205
205:115
Here I see 115 thread notified two threads, and 84 thread notified two threads; because of this we are seeing the ArrayIndexOutOfBoundsException.
115:84
115:111
84:203
84:200
ARRAYException:200:199:3
ARRAYException:203:199:3
What is the issue in the program?
What is the issue in the program?
You have a couple of problems with your code that may be causing this behavior. First, as #Holder commented on, there are a lot of code segments that can be run by multiple threads simultaneously that should be protected using synchronized blocks.
For example:
if (addIndex == capacity) {
addIndex = 0;
}
If multiple threads run this then multiple threads might see addIndex == capacity and multiple would be overwriting the 0th index. Another example is:
addIndex++;
This is a classic race condition if 2 threads try to execute this statement at the same time. If addIndex was 0 beforehand, after the 2 threads execute this statement, the value of addIndex might be 1 or 2 depending on the race conditions.
Any statements that could be executed at the same time by multiple threads have to be properly locked within a synchronized block or otherwise protected. Even though you have volatile fields, there can still be race conditions because there are multiple operations being executed.
Also, a classic mistake is to use if statements when checking for over or under flows on your array. They should be while statements to make sure you don't have the class consumer producer race conditions. See my docs here or take a look at the associated SO question: Why does java.util.concurrent.ArrayBlockingQueue use 'while' loops instead of 'if' around calls to await()?
Related
I am writing a thread safe counter. When I test and the threads go first one, then the second everything works correctly. But when threads enter the increment () method at the same time, the counter does not work properly. The reason is not clear, I am using atomic integer.
public class CASCount {
private final AtomicReference<Integer> count = new AtomicReference<>(0);
private AtomicInteger oldValue = new AtomicInteger(0);
private AtomicInteger newValue = new AtomicInteger(0);
public void increment() {
do {
oldValue.set(count.get());
System.out.println(oldValue + " old");
if (oldValue.get() == -1) {
throw new UnsupportedOperationException("Count is not impl.");
}
newValue.incrementAndGet();
System.out.println(newValue + " new");
} while (!count.compareAndSet(oldValue.get(), newValue.get()));
}
public int get() {
int result = -1;
result = count.get();
if (result == -1) {
throw new UnsupportedOperationException("Count is not impl.");
}
return result;
}
}
#Test
public void whenUseCASCount() throws InterruptedException {
CASCount count = new CASCount();
Thread one = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("one");
count.increment();
}
});
Thread two = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("two");
count.increment();
}
});
one.start();
two.start();
one.join();
two.join();
assertThat(count.get(), is(10));
}
its my decision
private final AtomicReference<Integer> count = new AtomicReference<>(0);
public void increment() {
int current, next;
do {
current = count.get();
next = current + 1;
} while (!count.compareAndSet(current, next));
}
public int get() {
return count.get();
}
TL;DR - Make your increment method synchronized.
Details - Even though you have atomic variables that you use, that does not mean that your class is thread safe. It's not safe because there can be (and are) race conditions between the checks and increments for your variables.
do {
oldValue.set(count.get());
System.out.println(oldValue + " old");
if (oldValue.get() == -1) {
throw new UnsupportedOperationException("Count is not impl.");
}
newValue.incrementAndGet(); <--- between here
System.out.println(newValue + " new");
} while (!count.compareAndSet(oldValue.get(), newValue.get())); <--- and here
A typical case of check-then-act race condition.
This happens because your atomic variables can be accessed by multiple threads and their shared state can mutate from one thread and not be seen in another.
To preserve state consistency, update related state variables in a single
atomic operation.
- Java Concurrency in Practice
Hence, we use intrinsic locks (built-in synchronized) to make the method safe when multiple threads access it. What happens is that the state of the atomic variables would not change because each thread will access the increment method one at a time.
I have been working on a school assignment which is about multithreading in Java. One of the tasks that I am stuck on is that we need to create multiple threads in different groups, and once there are 4 threads in each group, only then they can be released to work in unison, otherwise they have to be put on hold/waiting. For example:
Thread a,b,c joins group 7, they are all put on hold/waiting.
Thread d joins group 7, all four threads (a,b,c,d) are signaled to be terminated.
Thread e,f,g,h,i joins group 8, in this case e,f,g,h will be signalled to be terminated while thread i is put on waiting.
Thread j joins group 7, it is put on for waiting.
That is the general task which I'm done with. The task I am working on requires us to release the INITIAL first 4 threads of a group, and the rest should wait until 4 of the previous threads have called finished().
For example, 3 threads join group 65, they are put on wait. Another thread joins group 65 and all 4 threads are released together. Now 4 threads are working (terminated). Now thread e,f,g,h,i,j,k,l join group 65. All of them are put to wait until e,f,g,h have called finished() method.
Here is what I have done so far:
ExtrinsicSync.java:
import java.util.HashMap;
import java.util.concurrent.locks.ReentrantLock;
public class ExtrinsicSync {
private HashMap<Integer, ConditionWrapper> groupThreadCount;
private ReentrantLock monitor;
private int count = 0;
ExtrinsicSync() {
groupThreadCount = new HashMap<>();
monitor = new ReentrantLock();
}
#Override
public void waitForThreadsInGroup(int groupId) {
monitor.lock();
if (!groupThreadCount.containsKey(groupId))
groupThreadCount.put(groupId, new ConditionWrapper(monitor.newCondition()));
ConditionWrapper condWrapper = groupThreadCount.get(groupId);
condWrapper.setValue(condWrapper.getValue() + 1);
if(condWrapper.getValue() == 4 && condWrapper.getInitialStatus())
{
condWrapper.getCondition().signalAll();
condWrapper.setInitialStatus(false);
System.out.println("Terminating group: " + groupId + "FROM INITIAL STATE: " + ++count);
} else {
System.out.println("Putting thread from group: " + groupId + " on wait: " + ++waitcount);
try { condWrapper.getCondition().await(); }
catch (InterruptedException e) { e.printStackTrace(); }
}
monitor.unlock();
}
#Override
public void finished(int groupId) {
monitor.lock();
ConditionWrapper condWrapper = groupThreadCount.get(groupId);
if(!condWrapper.getInitialStatus())
{
condWrapper.setFinishedCount(condWrapper.getFinishedCount() + 1);
System.out.println("Group: " + groupId + "FINISHED COUNT: " + condWrapper.getFinishedCount());
if(condWrapper.getFinishedCount() == 4)
{
condWrapper.setFinishedCount(0);
condWrapper.getCondition().signalAll();
System.out.println("Terminating threads for group: " + groupId + ": " + ++count);
}
}
monitor.unlock();
}
ExtrinsicSyncTest.java:
import org.junit.Test;
import java.util.EnumMap;
class TestTask1 implements Runnable{
final int group;
final ExtrinsicSync s1;
TestTask1(int group, ExtrinsicSync s1)
{
this.group = group;
this.s1 = s1;
}
public void run() { s1.waitForThreadsInGroup(group); s1.finished(group); }
}
public class ExtrinsicSyncTest {
#Test
public void testPhaseThreethreads() {
int nThreads = 22;
Thread t[] = new Thread[nThreads];
final ExtrinsicSync s1 = new ExtrinsicSync();
for(int i = 0; i < nThreads/2; i++)
(t[i] = new Thread(new TestTask1(66, s1))).start();
for(int i = nThreads/2; i < nThreads; i++)
(t[i] = new Thread(new TestTask1(70, s1))).start();
for (Thread ti : t)
{
try { ti.join(100); }
catch (Exception e) { System.out.println(e); }
}
EnumMap<Thread.State, Integer> threadsInThisState = new EnumMap<>(Thread.State.class);
for (Thread.State s : Thread.State.values())
threadsInThisState.put(s, 0);
for (Thread ti : t)
{
Thread.State state = ti.getState();
int n = threadsInThisState.get(state);
threadsInThisState.put(state, n + 1);
}
System.out.println("threadsInThisState: " + threadsInThisState.toString() );
}
}
ConditionWrapper.java:
import java.util.concurrent.locks.Condition;
public class ConditionWrapper {
private Condition cond;
private Integer value;
private Integer finishedCount;
private boolean initialThreads;
public ConditionWrapper(Condition condition)
{
this.cond = condition;
this.value = 0;
this.finishedCount = 0;
this.initialThreads = true;
}
// Returns the condition object of current request
public Condition getCondition()
{
return this.cond;
}
// Gets the current counter of threads waiting in this queue.
public Integer getValue()
{
return this.value;
}
// Sets the given value. Used for resetting the counter.
public void setValue(int value) { this.value = value; }
// Sets the counter to help keep track of threads which called finished() method
public void setFinishedCount(int count) { this.finishedCount = count; }
// Gets the finished count.
public Integer getFinishedCount() { return this.finishedCount; }
// This flag is to identify initial threads of a group
public boolean getInitialStatus() { return initialThreads; }
public void setInitialStatus(boolean val) { this.initialThreads = val; }
}
The problem I am having is that I am able to release the first four threads of every group, but somehow, somewhere 2 threads are being terminated randomly and I cannot figure out what is going on. For example, with 22 threads test case above divided into two groups, only 8 threads should be terminated while the rest of them wait.
But here 10 threads are being terminated instead. I do not understand what is going on. I have stripped the code down to bare minimum as best as I could.
The problem is that for the not initial threads (getInitialStatus==false) you do not signal the other threads but you still terminate them when you reached four of them. So this is what happens:
first three threads increase the count and wait
the fourth thread reaches count == 4 and sets initial = false and signals all the other threads and sets the count to zero
the next three threads increase the count by one
the 8 threads reaches count == 4 and gets terminated. Since getInitialStatus==false this thread does not notify the other threads.
so 4*2 threads + 2 threads get terminated. Exactly the count you have seen in your tests.
Here is a potential way to implement this:
use a flag canExecute in each thread or task
use a method calculateState to calculate the current state and set the flag to true if a thread is allowed to execute.
store all threads which are waiting in a list or something similar
So your task would look like this:
Task
boolean canExeute
The method waitForThreadsInGroup then lookslike this:
waitForThreadsInGroup
monitor.lock();
add task to list
calculateTaskState
condition.notifyAll
while( ! task.canExcecute )
{
condition.await.
}
monitor.unlock();
The finish method looks similar:
finish
monitor.lock();
decrement finish count
calculateTaskState
condition.notifyAll
monitor.unlock();
And calculateTaskState
calculateTaskState
if( finishCount == 0)
{
if( taskList.size >= 4 )
{
set 4 tasks in this list to can execute and remove them from the list
}
}
So the trick is to separate the logic into three steps:
the action, for example reducing the finish count
the calculation of the new state. And deciding for each thread if it is allowed to execute
And the waiting of the threads. Each thread needs to wait on its own flag
I have applied two process critical section solution to two threads instead of processes. My code is:
class Main
{
static boolean flag[];
static int turn;
static int count;
synchronized static void print(char ch,int n)
{
int i;
System.out.println(ch);
for(i=0;i<n;i++){
System.out.println(i);
}
}
public static void main(String[] args) throws IOException
{
flag = new boolean[2];
flag[0] = flag[1] = false;
turn = 0;
count = 0;
ThreadLevelOne t1 = new ThreadLevelOne('a');
ThreadLevelTwo t2 = new ThreadLevelTwo('b');
t1.start();
t2.start();
}
static class ThreadLevelOne extends Thread{
private char ch;
public ThreadLevelOne(char ch){
this.ch = ch;
}
public void run(){
while(true)
{
flag[0] = true;
turn = 1;
while(flag[1] && turn == 1);
print(ch,3);
count++;
System.out.println("Counter is : " + count);
flag[0] = false;
}
}
}
static class ThreadLevelTwo extends Thread{
private char ch;
public ThreadLevelTwo(char ch){
this.ch = ch;
}
public void run()
{
while(true)
{
flag[1] = true;
turn = 0;
while(flag[0] && turn == 0);
print( ch, 4);
count++;
System.out.println("Counter is : " + count);
flag[1] = false;
}
}
}
}
On executing the above code, it does not run infinitely but halts at arbitrary counter value on each execution. Is this a valid application of the two process solution to threads? If yes, then why is program halting at arbitrary counter value? If no, then how can this be achieved in threads?
Edit after the answer of codeBlind:
output: Program execution halts at this stage
Even if i dont increment the counter value, then also the program halts after a certain time
You're a victim of concurrently executing non-atomic operations, specifically count++, as well as the way you are using flags in each thread. But for simplicity's sake, let's talk about count++. The ++ operator actually executes three commands, each in their own clock-cycle:
read value of count
add 1 to value retrieved from count
store new value into count
The problem you're seeing is a result of these commands being interleaved across two threads. Thread A may not have stored the new count value by the time that Thread B attempts to read it.
A quick fix would be to use AtomicInteger for count instead of primitive int - AtomicInteger guarantees thread safety for integer operations.
EDIT
There are other race conditions in this code as well. Each thread's while loop argument (e.g. flag[0] && turn == 0) is non-atomic, but both threads are capable of modifying turn. You've left open the possibility that one thread could set turn before the other thread's while argument is fully evaluated, causing your threads to deadlock down the road.
If you only wish to guarantee that each thread must not be inside the while loop while the other thread is, then you should instead write each of your while loops to look something like this:
while(true){
synchronized(Main.class){
print( ch, 4);
count++;
System.out.println("Counter is : " + count);
}
}
If you want to guarantee that each thread must "take turns", you should look into using wait() and notify().
Ok so I figured it out, the issue is that each thread needs to pause in order for the other thread to run.
Instead of just spinning the cpu using:
while(flag[0] && turn == 0);
You need to pause the thread by calling the sleep method.
while(flag[0] && turn == 0){
try {
this.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
So, I ran a test and the results make no sense to me. Lets consider the following code:
ThreadStuffCounter counter_1 = new ThreadStuffCounter(1);
while(counter_1.doProceed) {
Thread.sleep(500);
Thread thread = new Thread(counter_1);
thread.start();
}
With the Runnable as follows:
package test;
public class ThreadStuffCounter implements Runnable {
public volatile boolean doProceed = true;
private int id = -1;
public volatile int i = -1;
public ThreadStuffCounter(int id) {
this.id = id;
}
#Override
public void run() {
for (i = 0; i < 10; i++) {
System.out.println("i = " + i + " in runnable id = " + id);
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
doProceed = false;
}
}
Only one instance of counter is shared between threads. It takes less time for another thread to start then even one increment to be made on the counter.doProceed should, as I understand never be set to false and the loop should continue indefinitely until I get an out of memory exception and cannot start any more threads.
How is it possible for the loop to exit?
EDIT: Modified code to make sure the answer below is correct.
package test;
public class ThreadStuffCounter implements Runnable{
public volatile boolean doProceed = true;
private int id = -1;
volatile int i = -1;
public ThreadStuffCounter(int id){
this.id = id;
}
#Override
public void run() {
i = 0;
while (i < 10){
System.out.println("i = " + i + " in runnable id = " + id +
"; from thead id = " + Thread.currentThread().getId());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
ThreadStuff.doProceed = false;
}
}
And
package test;
public class ThreadStuff {
public static volatile boolean doProceed = true;
public static void main (String[] args) throws InterruptedException{
ThreadStuffCounter counter_1 = new ThreadStuffCounter(1);
while(doProceed){
Thread.sleep(500);
Thread thread = new Thread(counter_1);
thread.start();
}
}
}
Also, it appears more then n threads are needed if you are running for i < n. You need however many, so that n threads increment at the same time.
When at least one of the threads executes the for loop and i value is greater or equal than 10, then doProceed variable will be false (yes, this may happen), and since it's volatile this will stop the execution of the while loop that creates and starts new threads. Then, is up to all the threads to just finish executing the code of the for loop and then finishing their execution. This seems to happen because the time to start a new thread in your environment is slower than the time for a current thread to finish its execution. Also, note that several threads may increase i value, which will accelerate the for loop execution.
Probably if you loop to a higher value (not tested) then this could generate an infinite loop and the application will break when there aren't enough resources to create and start new threads.
After some tests using the limit as 10, 50 and 1000. I noticed that when you have a bigger value, since lots of threads are created, all of them increase the value of i at the same time and i slowly starts to get closer to the limit value set in the for loop. Description of my current environment:
OS: Windows 7 Professional 64 bits
Processor: Intel(R) Core(TM) i5-2520M CPU # 2.50GHz (4 CPUs), ~2.5GHz
Ram: 8192MB
Have a thread which produces random integers, and puts them into a list. Have also two threads which uses items up from the list concurrently. These threads need to sum up the items which they grab out of the list. Pause these threads until the list is filled. Then print out the summed results of the two threads.
I think, wait() and notify() should be used here. However, I'm not sure I properly understand how this works.
This thread grabs items from the list
#Override
public void run() {
try
{
while (list.size() > 0) {
synchronized (list) {
list.wait();
result += (Integer) list.remove(0);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
This is what fills the list.
#Override
public void run() {
try {
synchronized (list) {
list.wait();
for (int i = 0; i < 10; i++) {
list.add(random.nextInt());
System.out.println("fill");
}
list.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
However, they never finish.
Your code has a number of problem:
You claim to have two threads that read from the list, but you only show one.
You're accessing the list before locking it in the first code block. You need to put the synchronized(list) statement around the while loop.
The code that fills the list waits w/o having anything to notify it.
If your grab-items-from-the-list thread runs first, the list will be empty so it won't do anything. That's probably not what you want.
There is evidence of enough confusion here that I'd suggest trying to think this through in a more abstract way before jumping into writing code.
Well I think I too misunderstood the problem. Here is the correct solution.
This fills the list.
#Override
public void run() {
synchronized(list) {
for (int i = 0; i < 10; i++) {
list.add(random.nextInt());
}
list.notify();
}
}
This sums the items.
#Override
public void run() {
synchronized(list) {
while (list.size() > 0) {
result += (Integer) list.remove(0);
}
list.notify();
}
}
So they just have to lock the list itself, basically.
This, prints out the final solution:
try {
sum1.join();
sum2.join();
System.out.println(sum1.getResult() + sum2.getResult());
} catch (InterruptedException e) {
e.printStackTrace();
}
Anyway, I don't think concurrency implemented like this does not have any practical use - this was just a course task.
The notify() call in the filler thread only notifies one of the waiting threads. Only one thread proceeds to pull one integer. Then it waits again. With nothing firing a notify it waits forever. It needs to only wait if nothing is in the list.
Instead of reinventing the wheel use a BlockingQueue like so:
public Runnable createSum( final BlockingQueue<Integer> queue, final BlockingQueue<Integer> output ) {
return new Runnable() {
public void run() {
Integer result = 0;
while( !queue.isEmpty() ) {
result += queue.take();
}
output.put( result );
}
}
}
public void go() {
BlockingQueue<Integer> input = new ArrayBlockingQueue<Integer>();
BlockingQueue<Integer> output = new ArrayBlockingQueue<Integer>();
Thread runner1 = new Thread( createSum( input, output ) );
Thread runner2 = new Thread( createSum( input, output ) );
for( int i = 0; i < 10; i++ ) {
input.put( random.nextInt() );
}
runner1.start();
runner2.start();
runner1.join();
runner2.join();
Integer result = 0;
while( !output.isEmpty() ) {
result += output.take();
}
System.out.println( result );
}
This solution only starts summing things after the queue is filled but in your solution it was doing the same thing.