سؤال

I research concurrecy in java. Recently I learn wait and notify methods meaning.

Now I think that sometimes I should to solve following problem:

I have

class ThreadGroup1 extends Thread

and

class ThreadGroup2 extends Thread

I have 300 instances of every Thread and start simultaneously (for example by means of CountDownLatch )

And I have synchronized section:

synchronized(SharedObjectBetweenThreads){...}

I want to get following behaviour:

instance of ThreadGroup1 acquire the section

instance of ThreadGroup2 acquire the section

instance of ThreadGroup1 acquire the section

instance of ThreadGroup2 acquire the section

and so on.

I think you understand what I want.

I know that if I would use wait and notify I cannot guarantee which next thread from waiting queue will acquire section.

How can I solve described issue?

P.S.

This issue relates with question "how to notify concrete thread?"

P.S.

my current sketch

public class ConditionTest {
    public static void main(String [] args){
        List<Thread> threads = new ArrayList<>();
        for(int i=0 ;i<10;i++)  {
            threads.add(new Thread1());
            threads.add(new Thread2());
        }
        for(Thread thread : threads){
            thread.start();
        }
    }
    public static synchronized void method() throws InterruptedException {
         System.out.println(Thread.currentThread());
         Thread.sleep(500);

    }
}
class Thread1 extends Thread{
    static int index =0;
    int number;
    @Override
    public void run(){
        try {
            ConditionTest.method();
        } catch (InterruptedException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }
    @Override
     public String toString(){
        return "group1-" + number;
     }

    Thread1(){
        number= index++;
    }

}

class Thread2 extends Thread{
    static int index =0;
    int number;
    @Override
    public void run(){
        try {
            ConditionTest.method();
        } catch (InterruptedException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }
    @Override
    public String toString(){
        return "group2-" + number;
    }

    Thread2(){
       number= index++;
    }
}

please help to correct this.

According hoaz answer I got resolving.

please review this code:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class ConditionTest {
    static Integer CountThreadInGroup = 10;

    public static void main(String[] args) throws InterruptedException {

        Lock lock = new ReentrantLock();
        boolean isFirstShouldExecute = true;
        Condition isFirstExpected = lock.newCondition();
        Condition isSecondExpected = lock.newCondition() ;

        Synchronizator synchronizator = new Synchronizator(isFirstShouldExecute, lock,isFirstExpected,isSecondExpected);
        List<Thread> threads = new ArrayList<>();
        for (int i = 0; i < CountThreadInGroup; i++) {
            threads.add(new Thread1(synchronizator));
        }
        for (Thread thread : threads) {
            thread.start();
        }

        threads.clear();
        Thread.sleep(100);
        for (int i = 0; i < CountThreadInGroup; i++) {
            threads.add(new Thread2(synchronizator));
        }
        for (Thread thread : threads) {
            thread.start();
        }
    }

    public static void method() throws InterruptedException {

        System.out.println(Thread.currentThread());
        Thread.sleep(500);

    }
}

class Thread1 extends Thread {
    static int index = 0;
    int number;
    private final Synchronizator synchronizator;

    @Override
    public void run() {
        synchronizator.lock.lock();
        try {
            while (!synchronizator.isFirstExpected) {
                synchronizator.isFirstShouldExecute.await();
                System.out.println(Thread.currentThread() + " woke up");
            }
            ConditionTest.method();
            synchronizator.isFirstExpected = false;
            synchronizator.isSecondShouldExecute.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } finally {
            synchronizator.lock.unlock();
        }
    }

    @Override
    public String toString() {
        return "\t\t\t group1-" + number;
    }

    Thread1(Synchronizator synchronizator) {
        this.synchronizator = synchronizator;
        number = index++;
    }
}

class Thread2 extends Thread {
    static int index = 0;
    int number;
    private final Synchronizator synchronizator;

    @Override
    public void run() {
        synchronizator.lock.lock();
        try {
            while (synchronizator.isFirstExpected) {
                synchronizator.isSecondShouldExecute.await();
                System.out.println(Thread.currentThread() + " woke up");
            }
            ConditionTest.method();
            synchronizator.isFirstExpected = true;
            synchronizator.isFirstShouldExecute.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } finally {
            synchronizator.lock.unlock();
        }
    }

    @Override
    public String toString() {
        return "\t\t\t\t\t\t group2-" + number;
    }

    Thread2(Synchronizator synchronizator) {
        this.synchronizator = synchronizator;
        number = index++;
    }
}

class Synchronizator{

    volatile boolean isFirstExpected ;
    Lock lock ;
    Condition isFirstShouldExecute;
    Condition isSecondShouldExecute;

    Synchronizator(boolean  isFirstExpected, Lock lock, Condition isFirstShouldExecute, Condition isSecondShouldExecute){
        this.isFirstExpected = isFirstExpected;
        this.lock =lock;
        this.isFirstShouldExecute = isFirstShouldExecute;
        this.isSecondShouldExecute = isSecondShouldExecute;
    }
}
هل كانت مفيدة؟

المحلول

You can find Condition and ReentrantLock classes useful in this case:

Lock lock = new ReentrantLock();
Condition threadGroup1 = lock.newCondition();
Condition threadGroup2 = lock.newCondition();
volatile boolean isFirstGroupRunning = true;

Pass all four to each thread in both groups. You can actually compose them into new class. In first thread group use following code:

lock.lock();
try {
    while (!isFirstGroupRunning) threadGroup2.await();
    // do whatever you need to do in first thread
    isFirstGroupRunning = false;
    threadGroup1.signal();
} finally {
    lock.unlock();
}

In second thread group do similar await / signal sequence:

lock.lock();
try {
    while (isFirstGroupRunning) threadGroup1.await();
    // do whatever you need to do in second thread
    isFirstGroupRunning = true;
    threadGroup2.signal();
} finally {
    lock.unlock();
}

نصائح أخرى

First, I suggest you not extend Thread nor call the class ThreadGroup1, etc. ThreadGroup is a core class, and there is typically no reason to extend Thread. The best way to handle the logic executed in a thread is to implement Runnable and pass instances of that class to new Thread(myRunnableInstance).

I don't think I understand what you want to really do, but it doesn't sound like threads are the way to go. Threads are meant to run multiple process at the same time, not to do them in a sequence.

It sounds like you might want a different concurrent design, maybe a 'producer consumer model' if you have two separate 'Thread groups' that are acquiring a synchronised block sequentially. In which case you could have both thread groups interacting with the same BlockingQueue. It really depends on what these threads are doing.

See

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top