如何通过两组线程交替监视获取同步段?

时间:2014-04-25 18:04:50

标签: java multithreading concurrency synchronization

我在java中研究concurrecy。最近我学习等待并通知方法意义。

现在我认为有时我应该解决以下问题:

我有

class ThreadGroup1 extends Thread

class ThreadGroup2 extends Thread

我有300个每个线程的实例并同时启动(例如通过CountDownLatch)

我已经同步了一段:

synchronized(SharedObjectBetweenThreads){...}

我想获得以下行为:

instance of ThreadGroup1 acquire the section

instance of ThreadGroup2 acquire the section

instance of ThreadGroup1 acquire the section

instance of ThreadGroup2 acquire the section

等等。

我想你明白我的意思。

我知道如果我使用wait并通知我无法保证等待队列中的哪个下一个线程将获取部分。

如何解决所描述的问题?

P.S。

这个问题与问题"如何通知具体线程?"

P.S。

我当前的草图

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++;
    }
}

请帮助纠正此问题。

根据hoaz的回答,我得到了解决。

请查看此代码:

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;
    }
}

3 个答案:

答案 0 :(得分:1)

在这种情况下,您可以找到有用的ConditionReentrantLock类:

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

将所有四个传递给两个组中的每个线程。你实际上可以将它们组成新类。 在第一个线程组中使用以下代码:

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

在第二个线程组中执行类似的等待/信号序列:

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

答案 1 :(得分:0)

首先,我建议你不要扩展Thread,也不要调用类ThreadGroup1等.ThreadGroup是一个核心类,通常没有理由扩展Thread。处理线程中执行的逻辑的最佳方法是实现Runnable并将该类的实例传递给新的Thread(myRunnableInstance)。

我认为我不明白你想要做什么,但听起来不像是线程。线程意味着同时运行多个进程,而不是按顺序执行它们。

答案 2 :(得分:0)

听起来你可能想要一个不同的并发设计,如果你有两个独立的'线程组'正在顺序获取同步块,那么可能是'生产者消费者模型'。在这种情况下,您可以让两个线程组与相同的BlockingQueue交互。这实际上取决于这些线程在做什么。

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