Reputation: 276
Consider the following code
public class TestThreads {
public static void printListOfStrings(Collection<String> cs) {
for (String str : cs)
System.out.print(str + " by " + Thread.currentThread().getName());
System.out.println();
}
public static void main(String[] args) {
final List<String> lt1 = new ArrayList<>();
for (int i = 0; i < 5; i++)
lt1.add("string 1");
Thread thread1 = new Thread(" ONE ") {
@Override
public void run() {
printListOfStrings(lt1);
}
};
thread1.start();
final List<String> lt2 = new ArrayList<>();
for (int i = 0; i < 5; i++)
lt2.add("string 2");
Thread thread2 = new Thread(" TWO ") {
@Override
public void run() {
printListOfStrings(lt2);
}
};
thread2.start();
final List<String> lt3 = new ArrayList<>();
for (int i = 0; i < 5; i++)
lt3.add("string 1");
Thread thread3 = new Thread(" THREE ") {
@Override
public void run() {
printListOfStrings(lt3);
}
};
thread3.start();
}
}
The outputs of the code for the first run :
string 1 by ONE string 1 by ONE string 1 by ONE string 1 by ONE string 2 by TWO string 1 by ONE string 1 by THREE
string 2 by TWO string 2 by TWO string 2 by TWO string 2 by TWO
Second Run :
string 2 by TWO string 1 by THREE string 1 by ONE string 1 by THREE string 2 by TWO string 1 by THREE string 1 by ONE string 1 by THREE string 2 by TWO string 1 by THREE string 1 by ONE
string 2 by TWO string 2 by TWO
string 1 by ONE string 1 by ONE
string 1 by THREE string 1 by THREE string 1 by THREE string 1 by THREE
Now coming to the point, i dont have a problem when Thread ONE and Thread TWO concurrently running the for loop in printListOfStrings()
method. But Thread THREE which has identical list of strings as Thread A, should not be allowed to run along with Thread A. If thread A was started before thread C, A should be allowed to execute while C waits for it complete or if thread C was started before A, C should be allowed to execute while A waits for C to complete. what should i add in my printListOfStrings()
method to achieve this. Thanks in advance.
P.S: I dont want to use the synchronized key word any where because it is not giving the threads a fair chance to run (ie in the order threads came)
Upvotes: 3
Views: 67
Reputation: 100139
It's quite strange that you want to synchronize the threads which have the same list content (though the lists themselves are different which makes @RajSharma answer incorrect). Nevertheless here's how the problem can be solved with Java-8 ConcurrentHashMap
:
static ConcurrentHashMap<Collection<String>, Void> map = new ConcurrentHashMap<>();
public static void printListOfStrings(Collection<String> cs) {
map.computeIfAbsent(cs, k -> {
for (String str : cs)
System.out.print(str + " by " + Thread.currentThread().getName());
System.out.println();
return null;
});
}
The rest of the code is the same. Note that the map
always remains empty, we never add an element to it. However when computeIfAbsent
is running for single key, this key is blocked for other operations, but other keys can operate concurrently. Here as lt1
and lt3
lists are equal and have the same hashcode, their access is synchronized.
Upvotes: 1
Reputation: 136
The order in which the threads were started has no relevance. Once started they will run (nearly) concurrently. That is the whole point of threads.
If you wish for one of your thread to wait for something, you need to call the wait() method, and the other thread needs to notify() when done. And they both need to synchronise around the same object.
So create an object at the top of the method:
final Object syncOb = new Object();
In thread1 add after call to printListOfStrings:
synchronized (syncOb) {
syncOb.notify();
}
In thread3 add before call to printListOfStrings:
synchronized (syncOb) {
syncOb.wait();
}
Other threads will have a fair chance of running because they will not synchronize on syncOb.
Upvotes: 0
Reputation: 1971
You can use synchroize block like this---
public static void printListOfStrings(Collection<String> cs) {
synchronized(cs){
for (String str : cs)
System.out.print(str + " by " + Thread.currentThread().getName());
System.out.println();
}
}
Output-
string 1 by ONE string 1 by ONE string 1 by ONE string 1 by ONE string 1 by ONE
string 2 by TWO string 2 by TWO string 2 by TWO string 2 by TWO string 2 by TWO
1 by THREE string 1 by THREE string 1 by THREE string 1 by THREE string 1 by THREE
Upvotes: 0
Reputation: 3339
You can write the infintie loop in which you can check if t1 is completed before starting t3.
while(true){
if(t1.isAlive){
Thread.sleep(1000);
}else{
t3.start();
}
}
if you are using latest version of java, you can use Blocking Queque
Upvotes: 0