Tiny Rick
Tiny Rick

Reputation: 276

Queue the threads

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

Answers (4)

Tagir Valeev
Tagir Valeev

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

kresho
kresho

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

RajSharma
RajSharma

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

Panther
Panther

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

Related Questions