如何写下面的多线程程序最好的方法

时间:2016-08-04 08:54:19

标签: java multithreading

我是多线程新手,了解wait,notify和notifyAll的功能。我想要一个接一个地执行三个线程并从A到Z打印字母。 我尝试了下面的代码,它似乎也工作,但我怀疑这是否是解决问题的最佳方法。还有其他方法,我可以让它更简单,更好吗?似乎我的代码的某些部分正在重复。

package demo.threading;

class Flags {

    boolean flagA = true;
    boolean flagB = false;
    boolean flagC = false;

}

class Container {

    Flags flags = new Flags();
    int charVal = (int) 'A';

    void producer1() {

        try {
            while (charVal <= (int) 'Z') {
                synchronized (this) {
                    if (!flags.flagA)
                        wait();
                    else {
                        System.out.println(Thread.currentThread().getName() + " Produced : " + (char) charVal);
                        flags.flagA = false;
                        flags.flagB = true;
                        charVal++;
                        notifyAll();
                        Thread.sleep(1000);
                    }
                }
            }
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }

    }

    void producer2() {

        try {
            while (charVal <= (int) 'Z') {
                synchronized (this) {
                    if (!flags.flagB)
                        wait();
                    else {
                        System.out.println(Thread.currentThread().getName() + " Produced : " + (char) charVal);
                        flags.flagB = false;
                        flags.flagC = true;
                        charVal++;
                        notifyAll();
                        Thread.sleep(1000);
                    }
                }
            }
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    void producer3() {

        try {
            while (charVal <= (int) 'Z') {
                synchronized (this) {
                    if (!flags.flagC)
                        wait();
                    else {
                        System.out.println(Thread.currentThread().getName() + " Produced : " + (char) charVal);
                        flags.flagC = false;
                        flags.flagA = true;
                        charVal++;
                        notifyAll();
                        Thread.sleep(1000);
                    }
                }
            }
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

public class Main {
    public static void main(String[] args) {

        Container container = new Container();

        Thread t1 = new Thread(() -> container.producer1(), "Thread 1");
        Thread t2 = new Thread(() -> container.producer2(), "Thread 2");
        Thread t3 = new Thread(() -> container.producer3(), "Thread 3");

        t1.start();
        t2.start();
        t3.start();

    }
}

输出应为:

Thread 1 Produced : A
Thread 2 Produced : B
Thread 3 Produced : C
Thread 1 Produced : D
Thread 2 Produced : E
Thread 3 Produced : F

2 个答案:

答案 0 :(得分:4)

如前所述,如果你想要一个接一个地做到这一点&#34;,你实际上并不需要多个线程。但是,您可以使用Semaphore

来实现此目的
int numberOfThreads = 3;
Semaphore semaphore = new Semaphore(1);

for (int i = 1; i <= numberOfThreads; i++) {
    new Thread(() -> {
        try {
            semaphore.acquire();
            for (char c : "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray()) {
                System.out.println(Thread.currentThread().getName() 
                        + " produced: " + c + ".");
            }
        } catch (InterruptedException e) {
            // NOP
        } finally {
            semaphore.release();
        }
    }, "Thread " + i).start();
}

我建议探索自Java 5以来可用的java.util.concurrent。与Java的低级并发原语(如{1)相比,它可以帮助您保持并发代码简洁明了。 }和wait。如果您真的对该主题感兴趣,Brian Goetz's "Java Concurrency in Practice"是必读的。

修改

notify

答案 1 :(得分:0)

package demo.thread;

public class ABCPuzzle {

    private static class RunnableImpl implements Runnable {

        private String nextThread;
        private ExecServ execServ;

        public RunnableImpl(ExecServ execServ, String nextThread) {
            this.execServ = execServ;
            this.nextThread = nextThread;
        }

        @Override
        public void run() {

            String threadName = Thread.currentThread().getName();

            synchronized (execServ) {
                try {
                    while (true) {
                        if (execServ.key > 'Z')
                            break;

                        if (threadName.equals(execServ.current)) {
                            System.out.println(threadName + " consuming "  + execServ.key);
                            Thread.sleep(1000);
                            execServ.key++;
                            execServ.current = nextThread;
                            execServ.notifyAll();
                        } else
                            execServ.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static class ExecServ {
        private String current, next;
        private char key = 'A';
    }

    public static void main(String[] args) {

        ExecServ execServ = new ExecServ();
        execServ.current = "t1";

        Thread t1 = new Thread(new RunnableImpl(execServ, "t2"), "t1");
        Thread t2 = new Thread(new RunnableImpl(execServ, "t3"), "t2");
        Thread t3 = new Thread(new RunnableImpl(execServ, "t4"), "t3");
        Thread t4 = new Thread(new RunnableImpl(execServ, "t1"), "t4");

        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }
}

输出:

t1 consuming A
t2 consuming B
t3 consuming C
t4 consuming D
t1 consuming E
t2 consuming F
t3 consuming G
t4 consuming H
t1 consuming I
t2 consuming J