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
Related
I want to implement simple threadsafe counter. The numbers are in the right order so that part is ok, the only problem is the condition is not always met and sometimes the numbers go up to 51 or 52.
Should I use the tag synchronized also around the while loop?
I mean, I can double check and put a condition in the method printAndIncrement but that doesn't seem very elegant.
public class MyCounter implements Runnable {
static int currentValue = 0;
private static synchronized void printAndIncrement() {
System.out.print(Thread.currentThread().getName() + ": " + currentValue + "\n");
currentValue++;
}
#Override
public void run() {
while (currentValue <= 50) {
printAndIncrement();
}
}
public static void main(String[] args) {
MyCounter counter = new MyCounter();
Thread thread1 = new Thread(counter);
Thread thread2 = new Thread(counter);
Thread thread3 = new Thread(counter);
thread1.start();
thread2.start();
thread3.start();
}
}
The check currentValue <= 50 and the call to printAndIncrement must be in the same synchronized block. Otherwise this problem is going to happen.
Let currentValue be 50. All three threads can do the check that the current value is no more than 50 and then try to call printAndIncrement(); simultaneously.
Due to the synchronized void printAndIncrement() the threads will execute this method sequentially, but for the first thread the currentValue will be 50, for the second thread it will be 51 and for the third thread it will be 52.
The problem is that your boundary check and the increment are not both synchronized, which defeats the point of synchronization altogether.
The best alternative I can suggest that allows both synchronizing read/update and allowing your loop to stop would be to make the incrementing method return a boolean:
/** Prints and increments, returning true if max value has not been reached */
private static synchronized boolean printAndIncrement() {
if(currentValue < 51) {
System.out.print(Thread.currentThread().getName()
+ ": " + currentValue + "\n");
currentValue++;
return true;
} else {
return false;
}
}
And change the run method to:
public void run() {
while (printAndIncrement()) {
//nothing needs to be done here
}
}
I'm trying to get into the nitty gritty of understanding how wait and notifyAll work and have hit a roadblock.
This program downloads a long text document, starts multiple threads to count characters and then outputs the count totals.
I'm using wait and notifyAll to control the thread execution so that they are completed in alphabetical order. Here's the code. I'll follow with an explanation of the problem.
public class Test {
public static void main(String[] args) {
//code that reads in the data
LongTask a = new LongTask(buffer, 'a', "Thread_a", 0);
a.start();
LongTask b = new LongTask(buffer, 'b', "Thread_b", 1);
b.start();
//Repeat code for all other characters
a.join();
System.out.println("Alphabet count is: " + SharedResults.getResults());
LongTask class contains constructor and run()
public class LongTask extends Thread {
//Instance variables created here
//LongTask constructor
public LongTask (StringBuffer buffer, char target, String name, int turn)
{
super(name);
this.sharedData = sharedData;
inputData = buffer;
this.target = target;
this.turn = turn;
}
//Run method iterates through input data and counts matching characters,
//then calls addToResults
public synchronized void run()
{
//Thread t = Thread.currentThread();
String name = this.getName();
int runTurn = this.turn;
System.out.println(name + " running - Turn " + runTurn);
Integer count = 0;
for (int i = 0; i < inputData.length(); i++) {
if (inputData.charAt(i) == target) {
count ++;
}
}
ResultsEntry newResult = new ResultsEntry(count, target);
SharedResults.addToResults(newResult, turn);
}
}
SharedResults class adds results to Array. addToResults method performs this action and controls the synchronization.
public class SharedResults extends Thread{
//Code that creates array
//Code for SharedResults constructor
public synchronized static void addToResults(ResultsEntry newResult, int turn)
{
Integer resultsCount = newResult.getCount();
char resultsTarget = newResult.getTarget();
Thread t = Thread.currentThread();
/*
* Turn number is compared to the size of the results array to control the
* order of execution.
*/
while (turn != results.size()){
try {
System.out.println("Wait printout");
t.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(t.getName() + " is adding " + newResult);
SharedResults input = new SharedResults(resultsCount, resultsTarget);
System.out.println("Cumulative Results are " + results);
t.notifyAll();
}
Here's what I'm seeing when I watch this step through in Debug.
-Input executes and all LongTask threads start
(Thread_a should be the first thread to execute addToResults)
-Some threads (not Thread_a) hit the while evaluation of addToResults and do not proceed
-Thread_a hits the while evaluation and fully executes. (Now it should be Thread_b's turn)
-Thread_e executes the "Wait printout" (just a debugging feature that tells me when a thread is waiting) and then the program hangs.
It looks to me like I haven't set up wait correctly. The program actually worked (or appeared to be) correctly until I added in the sysout. Any ideas what's going on here?
To answer my own question,
This was covered in this thread.
The problem is that notifyAll() notify all of that object's threads that are waiting. Because I was calling wait() on each thread, the notifyAll() from another thread wasn't notifying any of the other threads.
As suggested by the linked post, I created a static synchronized object and called the wait and notify methods on that object. The resulting code looked like this:
private static final Object LOCK = new Object();
public static void addToResults(ResultsEntry newResult, int turn)
{
Integer resultsCount = newResult.getCount();
char resultsTarget = newResult.getTarget();
Thread thread = Thread.currentThread();
/*
* Turn number is compared to the size of the results array to control the
* order of execution.
*/
synchronized (LOCK){
while (turn != results.size()){
try {
System.out.println(thread.getName() + " is waiting");
LOCK.wait();
} catch (InterruptedException e) {}
}
System.out.println(thread.getName() + " is adding " + newResult);
SharedResults input = new SharedResults(resultsCount, resultsTarget);
System.out.println("Cumulative Results are " + results);
LOCK.notifyAll();
}
}
Thanks to all who commented!
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()?
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