同步三个线程

时间:2014-10-02 16:46:29

标签: java multithreading java.util.concurrent

在接受采访时被问到这个问题,试图解决它......但没有成功。 我想过使用CyclicBarrier

有三个线程T1打印1,4,7 ... T2打印2,5,8 ...... T3打印3,6,9 ....如何将这三个同步到打印序列1,2,3,4,5,6,7,8,9 ....

我试过写作&运行以下代码

public class CyclicBarrierTest {
    public static void main(String[] args) {
        CyclicBarrier cBarrier = new CyclicBarrier(3);
        new Thread(new ThreadOne(cBarrier,1,10,"One")).start();
        new Thread(new ThreadOne(cBarrier,2,10,"Two")).start();
        new Thread(new ThreadOne(cBarrier,3,10,"Three")).start();
    }
}

class ThreadOne implements Runnable {
    private CyclicBarrier cb;
    private String name;
    private int startCounter;
    private int numOfPrints;

    public ThreadOne(CyclicBarrier cb, int startCounter,int numOfPrints,String name) {
        this.cb = cb;
        this.startCounter=startCounter;
        this.numOfPrints=numOfPrints;
        this.name=name;
    }

    @Override
    public void run() {
        for(int counter=0;counter<numOfPrints;counter++)
        {
            try {
            // System.out.println(">>"+name+"<< "+cb.await());
            cb.await();
            System.out.println("["+name+"] "+startCounter);
            cb.await();
            //System.out.println("<<"+name+">> "+cb.await());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        startCounter+=3;
        }
    }

}

输出

[Three] 3
[One] 1
[Two] 2
[One] 4
[Two] 5
[Three] 6
[Two] 8
[One] 7
[Three] 9
[One] 10
[Two] 11
[Three] 12
[Two] 14
[One] 13
[Three] 15
[One] 16
[Two] 17
[Three] 18
[Two] 20
[One] 19
[Three] 21
[One] 22
[Two] 23
[Three] 24
[Two] 26
[One] 25
[Three] 27
[One] 28
[Two] 29
[Three] 30

任何人都可以帮我正确的答案吗?

类似的问题 Thread Synchronization - Synchronizing three threads to print 012012012012..... not working

5 个答案:

答案 0 :(得分:2)

是否要求使用 CyclicBarrier?我的建议是:

  1. 为每个ThreadOne实例分配两个CyclicBarriers
  2. 您应该创建一个循环图,以便

    ThreadOne_1 -> ThreadOne_2 -> ThreadOne_3 -> ThreadOne_1 -> etc...

  3. 要实现(2)你需要与孩子分享父母的CyclicBarrier,并且最后一个任务应该与第一个Thread的孩子分享它的CB。
  4. 回答你的问题:

      

    尝试浏览文档,但不太清楚await()究竟做了什么......

    Await将暂停,直到N个线程在屏障上调用await。因此,如果您定义new CyclicBarrier(3)而不是一次3个线程调用await,则屏障将允许线程继续。

      

    何时使用reset()

    您不需要,一旦线程数量达到

    ,它将自动跳闸

答案 1 :(得分:2)

正如其他人已经提到的,CyclicBarrier并不是完成任务的最佳工具。

我也同意这样的观点,即解决方案是链接线程,让一个线程始终为下一个线程设置。

这是一个使用Semaphore的实现:

import java.util.concurrent.BrokenBarrierException; 
import java.util.concurrent.Semaphore;

public class PrintNumbersWithSemaphore implements Runnable {

private final Semaphore previous;

private final Semaphore next;

private final int[] numbers;

public PrintNumbersWithSemaphore(Semaphore previous, Semaphore next, int[] numbers) {
    this.previous = previous;
    this.next = next;
    this.numbers = numbers;
}

@Override
public void run() {

    for (int i = 0; i < numbers.length; i++) {
        wait4Green();

        System.out.println(numbers[i]);

        switchGreen4Next();
    }
}

private void switchGreen4Next() {
        next.release();
}

private void wait4Green() {
    try {
        previous.acquire();
    } catch (InterruptedException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
}

static public void main(String argv[]) throws InterruptedException, BrokenBarrierException {
    Semaphore sem1 = new Semaphore(1);
    Semaphore sem2 = new Semaphore(1);
    Semaphore sem3 = new Semaphore(1);
    sem1.acquire();
    sem2.acquire();
    sem3.acquire();
    Thread t1 = new Thread(new PrintNumbersWithSemaphore(sem3, sem1, new int[] { 1, 4, 7 }));
    Thread t2 = new Thread(new PrintNumbersWithSemaphore(sem1, sem2, new int[] { 2, 5, 8 }));
    Thread t3 = new Thread(new PrintNumbersWithSemaphore(sem2, sem3, new int[] { 3, 6, 9 }));
    t1.start();
    t2.start();
    t3.start();
    sem3.release();

    t1.join();
    t2.join();
    t3.join();
}

}

另外一个,在我看来,使用CyclicBarrier非常麻烦:

import java.util.concurrent.BrokenBarrierException; 
import java.util.concurrent.CyclicBarrier;

public class PrintNumbersWithCyclicBarrier implements Runnable {

private final CyclicBarrier previous;

private final CyclicBarrier next;

private final int[] numbers;

public PrintNumbersWithCyclicBarrier(CyclicBarrier previous, CyclicBarrier next, int[] numbers) {
    this.previous = previous;
    this.next = next;
    this.numbers = numbers;
}

@Override
public void run() {

    for (int i = 0; i < numbers.length; i++) {
        wait4Green();

        System.out.println(numbers[i]);

        switchRed4Myself();

        switchGreen4Next();
    }
}

private void switchGreen4Next() {
    try {
        next.await();
    } catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
}

private void switchRed4Myself() {
    previous.reset();
}

private void wait4Green() {
    try {
        previous.await();
    } catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
}

static public void main(String argv[]) throws InterruptedException, BrokenBarrierException {
    CyclicBarrier cb1 = new CyclicBarrier(2);
    CyclicBarrier cb2 = new CyclicBarrier(2);
    CyclicBarrier cb3 = new CyclicBarrier(2);
    Thread t1 = new Thread(new PrintNumbersWithCyclicBarrier(cb3, cb1, new int[] { 1, 4, 7 }));
    Thread t2 = new Thread(new PrintNumbersWithCyclicBarrier(cb1, cb2, new int[] { 2, 5, 8 }));
    Thread t3 = new Thread(new PrintNumbersWithCyclicBarrier(cb2, cb3, new int[] { 3, 6, 9 }));
    t1.start();
    t2.start();
    t3.start();
    cb3.await();

    t1.join();
    t2.join();
    t3.join();
}

}

答案 2 :(得分:0)

这是一种使用synchronized,wait和notifyAll对任意数量的线程起作用的方法 turn变量控制哪个是必须执行的线程。这样的线程执行任务,增加turn(以模数线程),通知所有线程并进入while循环等待直到轮到它为止。

public class Test2 {

    final static int LOOPS = 10;
    final static int NUM_TREADS = 3;

    static class Sequenced extends Thread {

        static int turn = 0;
        static int count = 0;
        static Object lock = new Object();
        final int order;

        public Sequenced(int order) {
            this.order = order;
        }

        @Override
        public void run() {
            synchronized (lock) {
                try {
                    for (int n = 0; n < LOOPS; ++n) {
                        while (turn != order) {
                            lock.wait();
                        }
                        ++count;
                        System.out.println("T" + (order + 1) + " " + count);
                        turn = (turn + 1) % NUM_TREADS;
                        lock.notifyAll();
                    }
                } catch (InterruptedException ex) {
                    // Nothing to do but to let the thread die.
                }
            }
        }
    }

    public static void main(String args[]) throws InterruptedException {
        Sequenced[] threads = new Sequenced[NUM_TREADS];
        for (int n = 0; n < NUM_TREADS; ++n) {
            threads[n] = new Sequenced(n);
            threads[n].start();
        }
        for (int n = 0; n < NUM_TREADS; ++n) {
            threads[n].join();
        }
    }

}

答案 3 :(得分:0)

由于螺纹应该具有相同的重量,即在第三个之后的第二个之后。以下作品。

public class MultiThreadSynchronize {

static int index = 0;
static Object lock = new Object();

static class NumberPrinter extends Thread {
    private final int remainder;
    private final int noOfThreads;
    private int value;

    public NumberPrinter(String name, int remainder, int noOfThreads, int value) {
        super(name);
        this.remainder = remainder;
        this.noOfThreads = noOfThreads;
        this.value = value;
    }

    @Override
    public void run() {
        while (index < 20) {
            synchronized (lock) {
                while ((index % noOfThreads) != remainder) {. // base condition where all threads except one waits.
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                index++;
                System.out.println(getName() + " " + value);
                value += 3;
                lock.notifyAll();
            }
        }
    }
}

public static void main(String[] args) {
    NumberPrinter numberPrinter1 = new NumberPrinter("First Thread", 0, 3, 1);
    NumberPrinter numberPrinter2 = new NumberPrinter("Second Thread", 1, 3, 2);
    NumberPrinter numberPrinter3 = new NumberPrinter("Third Thread", 2, 3, 3);
    numberPrinter1.start(); numberPrinter2.start(); numberPrinter3.start();
}
}

答案 4 :(得分:0)

我已经使用事件对一个三线程应用程序进行了编码

#include <iostream>
#include <Windows.h>
#include <atomic>
using namespace std;


HANDLE firstThreadEvent = CreateEvent(NULL, true, true, NULL);
HANDLE secondThreadEvent = CreateEvent(NULL, true, false, NULL);
HANDLE thirdThreadEvent = CreateEvent(NULL, true, false, NULL);
std::atomic<int> m_int = 1;

DWORD WINAPI firstThreadFun(LPVOID lparam)
{
    while (1)
    {
        ::WaitForSingleObject(firstThreadEvent,INFINITE);
        cout << "By first thread " << m_int << std::endl;
        m_int++;
        ResetEvent(firstThreadEvent);
        SetEvent(secondThreadEvent);

    }
}
DWORD WINAPI secondThreadFun(LPVOID lparam)
{
    while (1)
    {
        ::WaitForSingleObject(secondThreadEvent, INFINITE);
        cout << "By second thread "<< m_int << std::endl;
        m_int++;
        ResetEvent(secondThreadEvent);
        SetEvent(thirdThreadEvent);

    }

}
DWORD WINAPI thirdThreadFun(LPVOID lparam)
{
    while (1)
    {
        ::WaitForSingleObject(thirdThreadEvent, INFINITE);
        cout << "By third thread " << m_int << std::endl;
        m_int++;
        ResetEvent(thirdThreadEvent);
        SetEvent(firstThreadEvent);

    }
}



int main()
{
    HANDLE hnd[3];
    hnd[0] = CreateThread(NULL, 0, &firstThreadFun, NULL, 0, NULL);
    hnd[1] = CreateThread(NULL, 0, &secondThreadFun, NULL, 0, NULL);
    hnd[2] = CreateThread(NULL, 0, &thirdThreadFun, NULL, 0, NULL);

    WaitForMultipleObjects(3, hnd, true, INFINITE);
    CloseHandle(hnd[0]);
    CloseHandle(hnd[1]);
    CloseHandle(hnd[2]);
    return 0;
}