15

我有 3 个线程 第 1 次打印 A 第 2 次打印 B 第 3 次打印 C

我想按顺序打印 ABCABCABC 等等.....

所以我写了下面的程序,但我无法实现。我知道当状态 = 1 时,例如 B1 和 C1 线程正在等待,当我执行 notifyAll() 时,两个等待线程都会唤醒,并且根据 CPU 分配,它可能会打印 B 或 C。

在这种情况下,我只想在 A 之后打印 B。

我需要做什么修改。

public class NotifyAllExample {

    int status=1;
    public static void main(String[] args) {

        NotifyAllExample notifyAllExample = new NotifyAllExample();

        A1 a=new A1(notifyAllExample);
        B1 b=new B1(notifyAllExample);
        C1 c=new C1(notifyAllExample);

        a.start();
        b.start();
        c.start();
    }
}

class A1 extends Thread{
    NotifyAllExample notifyAllExample;

    A1(NotifyAllExample notifyAllExample){
        this.notifyAllExample = notifyAllExample;
    }

    @Override
    public void run() {

        try{
            synchronized (notifyAllExample) {

                for (int i = 0; i < 100; i++) {

                    if(notifyAllExample.status!=1){
                        notifyAllExample.wait();
                    }

                    System.out.print("A ");
                    notifyAllExample.status = 2;
                    notifyAllExample.notifyAll();
                }

            }
        }catch (Exception e) {
            System.out.println("Exception 1 :"+e.getMessage());
        }

    }

}

class B1 extends Thread{

    NotifyAllExample notifyAllExample;

    B1(NotifyAllExample notifyAllExample){
        this.notifyAllExample = notifyAllExample;
    }

    @Override
    public void run() {

        try{
            synchronized (notifyAllExample) {

                for (int i = 0; i < 100; i++) {

                    if(notifyAllExample.status!=2){
                        notifyAllExample.wait();
                    }

                    System.out.print("B ");
                    notifyAllExample.status = 3;
                    notifyAllExample.notifyAll();
                }

            }
        }catch (Exception e) {
            System.out.println("Exception 2 :"+e.getMessage());
        }

    }
}


class C1 extends Thread{

    NotifyAllExample notifyAllExample;

    C1(NotifyAllExample notifyAllExample){
        this.notifyAllExample = notifyAllExample;
    }

    @Override
    public void run() {

        try{
            synchronized (notifyAllExample) {

                for (int i = 0; i < 100; i++) {

                    if(notifyAllExample.status!=3){
                        notifyAllExample.wait();
                    }

                    System.out.print("C ");
                    notifyAllExample.status = 1;
                    notifyAllExample.notifyAll();
                }

            }
        }catch (Exception e) {
            System.out.println("Exception 3 :"+e.getMessage());
        }

    }
}
4

10 回答 10

14

将这些 IF 语句转换为 WHILE 语句以获得所需的行为:

if (notifyAllExample.status != 2){
    notifyAllExample.wait();
}

while (notifyAllExample.status != 2){
    notifyAllExample.wait();
}

这将确保如果一个线程被通知,它不会退出 while 循环,直到状态值是它所期望的值。

此外,标记status为 volatile 以便线程不会有本地副本。

于 2012-10-20T14:34:07.987 回答
7
 public class RunThreadsInOrder implements Runnable {

    static int numThread = 1;
    static int threadAllowedToRun = 1;
    int myThreadID;
    private static Object myLock = new Object();

    public RunThreadsInOrder() {
        this.myThreadID = numThread++;
        System.out.println("Thread ID:" + myThreadID);
    }

    @Override
    public void run() {
        synchronized (myLock) {
            while (myThreadID != threadAllowedToRun) {
                try {
                    myLock.wait();
                } catch (InterruptedException e) {

                } catch (Exception e) {}
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }

            System.out.println("myThreadID is running: " + myThreadID);
            myLock.notifyAll();
            threadAllowedToRun++;
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Thread t1 = new Thread(new RunThreadsInOrder());
        Thread t2 = new Thread(new RunThreadsInOrder());
        Thread t3 = new Thread(new RunThreadsInOrder());
        Thread t4 = new Thread(new RunThreadsInOrder());
        Thread t5 = new Thread(new RunThreadsInOrder());
        Thread t6 = new Thread(new RunThreadsInOrder());
        Thread t7 = new Thread(new RunThreadsInOrder());

        t7.start();
        t6.start();
        t5.start();
        t4.start();
        t3.start();
        t2.start();
        t1.start();

    }
}
于 2014-04-16T02:19:50.830 回答
1
    public class Main {
        public static void main(String[] args) throws IOException{
        Thread t1 = new Thread(new A(), "1");
        Thread t2 = new Thread(new A(), "2");
        Thread t3 = new Thread(new A(), "3");

        t1.start();
        try{
            t1.join();
        }catch (Exception e){

        }
        t2.start();
        try{
            t2.join();
        }catch (Exception e){

        }
        t3.start();
        try{
            t3.join();
        }catch (Exception e){

        }


    }
}

    class A implements Runnable{
    public void run(){
        System.out.println(Thread.currentThread().getName());
    }
}

或者你可以使用 Executor Framework

public class Sequence {
    int valve = 1;
    public static void main(String[] args){
        Sequence s = new Sequence();
        ExecutorService es = Executors.newFixedThreadPool(3);

        List<Runnable> rList = new ArrayList<>();
        rList.add(new A(s));
        rList.add(new B(s));
        rList.add(new C(s));

        for(int i = 0; i < rList.size(); i++){
            es.submit(rList.get(i));
        }
        es.shutdown();

    }
}

class A implements Runnable{
    Sequence s;

    A(Sequence s){
        this.s = s;
    }

    public void run(){
        synchronized (s) {
            for (int i = 0; i < 10; i++) {
                while (s.valve != 1) {
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("A");
                s.valve = 2;
                s.notifyAll();
            }
        }
    }
}

class B implements Runnable{
    Sequence s;

    B(Sequence s){
        this.s = s;
    }

    public void run() {
        synchronized (s) {
            for (int i = 0; i < 10; i++) {
                while (s.valve != 2) {
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("B");
                s.valve = 3;
                s.notifyAll();
            }
        }
    }
}

class C implements Runnable{
    Sequence s;

    C(Sequence s){
        this.s = s;
    }

    public void run() {
        synchronized (s) {
            for(int i = 0; i < 10; i++) {
                while (s.valve != 3) {
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("C");
                s.valve = 1;
                s.notifyAll();
            }
        }
    }
}

在第一种情况下,每个线程的连接导致线程相互等待。在第二种情况下,一个列表存储线程,执行器一个接一个地执行它们,创建 3 个线程

另一种方法是只存在一个可运行类,线程之间的通信通过主类中的静态变量和可运行类中的变量完成

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Seq {
    int i = 1;
    public static void main(String[] args){
        Seq s = new Seq();
        Common c1 = new Common(s, 1);
        Common c2 = new Common(s, 2);
        Common c3 = new Common(s, 3);

        List<Runnable> l = new ArrayList<>();
        l.add(c1);
        l.add(c2);
        l.add(c3);

        ExecutorService es = Executors.newFixedThreadPool(3);
        for(int i = 0; i < 3; i++){
            es.submit(l.get(i));
        }
        es.shutdown();
    }
}

class Common implements Runnable{
    Seq s;
    int o;

    Common(Seq s, int o){
        this.s = s;
        this.o = o;
    }

    public void run(){
        synchronized (s) {
            for (int z = 0; z < 100; z++) {
                if(s.i > 3)
                    s.i = 1;
                while (s.i != o) {
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(o);
                s.i++;
                s.notifyAll();
            }
        }
    }
}
于 2016-08-05T08:15:43.693 回答
1

在一次采访中,我被要求编写一个类似的程序,附加条件是它应该是可扩展的,我们可以提供我们自己的线程数,并且它们应该打印字符,第一个线程打印“A”,然后是后续线程印刷B、C、D等。这就是我的做法。

public class AlternateCharPrinter {

    public static char ch = 65;

    private static void createAndStartThreads(int count) {
        Object lock = new Object();
        for (int i = 0; i < count; i++) {
            new Thread(new AlternateCharRunner((char) (65 + i), lock)).start();
        }

    }

    public static void main(String[] args) {
        createAndStartThreads(4);
    }

}

class AlternateCharRunner implements Runnable {

    private char ch;
    private Object lock;
    private static int runnerCount;

    public AlternateCharRunner(char ch, Object lock) {
        this.ch = ch;
        this.lock = lock;
        runnerCount++;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (lock) {
                while (ch != AlternateCharPrinter.ch) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(AlternateCharPrinter.ch++);
                if (AlternateCharPrinter.ch == (65 + runnerCount)) {
                    AlternateCharPrinter.ch = 65;
                }
                lock.notifyAll();
            }
        }
    }

}
于 2017-02-28T18:28:23.073 回答
0

你需要更换

if (notifyAllExample.status!=1)

while (notifyAllExample.status!=1)

在其他 2 个班级中也是如此。如果不是,那么一旦等待退出,线程就会继续,而不知道是否轮到它了。

于 2012-10-20T14:32:43.697 回答
0

代替:

if(notifyAllExample.status!=1){
   notifyAllExample.wait();
}

和:

while(notifyAllExample.status!=1){
   notifyAllExample.wait();
}

相应地在所有课程中。

于 2012-10-20T14:33:34.147 回答
0

解决此问题的最简单解决方案可以是以下方式:

public class PrintInOrder implements Runnable {

private int valueToPrint;
private int id;
private static int turn = 1;
private static int RESET_TURN_THRESHOLD = 3;

public PrintInOrder() {
    this.valueToPrint = -1;
}

public PrintInOrder(int id, int val) {
    this.id = id;
    this.valueToPrint = val;
}

@Override
public void run() {
        while(true) {
            if (turn == this.id) {
                System.out.println(Thread.currentThread().getName() + "::::" + valueToPrint);
                turn++;
            }
            if (turn > RESET_TURN_THRESHOLD) {
                turn = 1;
            }
        }

}

public static void main(String []args) {
    Thread t1 = new Thread(new PrintInOrder(1, 1));
    t1.setName("THREAD-1");
    t1.start();
    Thread t2 = new Thread(new PrintInOrder(2, 2));
    t2.setName("THREAD-2");
    t2.start();
    Thread t3 = new Thread(new PrintInOrder(3, 3));
    t3.setName("THREAD-3");
    t3.start();
}

}

/*
OUTPUT::::
THREAD-1::::1
THREAD-2::::2
THREAD-3::::3
THREAD-1::::1
THREAD-2::::2
THREAD-3::::3
THREAD-1::::1
THREAD-2::::2
THREAD-3::::3
THREAD-1::::1
THREAD-2::::2
THREAD-3::::3
THREAD-1::::1
THREAD-2::::2
THREAD-3::::3
THREAD-1::::1
THREAD-2::::2
THREAD-3::::3
...
*/
于 2017-11-17T19:39:41.997 回答
0

这是我的解决方案 -

我创建了三个线程,每个线程都知道它需要打印什么以及之后会发生什么。

我还创建了一个 NLock 类,它保存下一个需要打印的单词。

每当一个线程能够获取 NLock 锁时,它会检查是否轮到他,如果是,则打印该单词并设置要在 NLock 中打印的下一个值,否则它会等到轮到他

public class SynchronizeThreeThreads {

    public static void main(String args[]) throws InterruptedException {
        NLock lock=new NLock("A");
        Thread a =new Thread(new PrintInOrder("A","B",lock));
        Thread b =new Thread(new PrintInOrder("B","C",lock));
        Thread c =new Thread(new PrintInOrder("C","A",lock));

        a.start();
        b.start();
        c.start();
        c.join(); // Once all is done main thread will exit
        System.out.println("Done");
    }
}

class NLock{
     private String value;

     public NLock(String value) {
         this.value=value;
     }

     public String getValue() {
         return value;
     }

     public void setValue(String next) {
         this.value=next;
     }

}

class PrintInOrder implements Runnable{

    private String word;

    private String next;

    private NLock lock;

    public PrintInOrder(String word, String next,NLock lock){
        this.word=word;
        this.next=next;
        this.lock=lock;
    }

    @Override
    public void run() {
        int i=0;
        while(i<3) {
            synchronized (lock) {
                try {
                    //Check if it's my turn
                    if(lock.getValue().equals(word)) {
                        System.out.println(this.word);
                        //Set what next needs to be printed
                        //So that when that thread wakes up it knows that it's his turn
                        lock.setValue(next);
                        i++;
                        lock.notifyAll();
                        Thread.sleep(100);
                    }
                    else //Nope not my turn wait
                        lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}

下面是输出

A B C A B C A B C 完成

于 2020-05-28T00:19:13.683 回答
-1

我认为使用连接来实现这一点更简单。例子:

    public static void main(String[] args) {    
    final Thread t1 = new Thread("t1") {
        @Override
        public void run() {
            System.out.println("i am thread: " + Thread.currentThread().getName());
        }
    };

    final Thread t2 = new Thread(t1, "t2") {
        @Override
        public void run() {
            t1.start();
            try {
                t1.join();
            } catch ( InterruptedException e ) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("i am thread: " + Thread.currentThread().getName());
        }
    };

    Thread t3 = new Thread(t2, "t3") {
        @Override
        public void run() {
            t2.start();
            try {
                t2.join();
            } catch ( InterruptedException e ) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("i am thread: " + Thread.currentThread().getName());
        }
    };

    t3.start();

}

于 2014-05-03T23:58:58.577 回答
-1

这是我的解决方案,请尝试让我知道

package thread;

class SyncPrinter {
    public static void main(String[] args) {
        SyncPrinterAction printAction1 = new SyncPrinterAction(new int[]{1,5,9,13}, true);
        SyncPrinterAction printAction2 = new SyncPrinterAction(new int[]{2,6,10,14}, true);
        SyncPrinterAction printAction3 = new SyncPrinterAction(new int[]{3,7,11,15}, true);
        SyncPrinterAction printAction4 = new SyncPrinterAction(new int[]{4,8,12,16}, false);

        printAction1.setDependentAction(printAction4);
        printAction2.setDependentAction(printAction1);
        printAction3.setDependentAction(printAction2);
        printAction4.setDependentAction(printAction3);

        new Thread(printAction1, "T1").start();;        
        new Thread(printAction2, "T2").start();
        new Thread(printAction3, "T3").start();     
        new Thread(printAction4, "T4").start();



    }
}

class SyncPrinterAction implements Runnable {

    private volatile boolean dependent;
    private SyncPrinterAction dependentAction;
    int[] data;

    public void setDependentAction(SyncPrinterAction dependentAction){
        this.dependentAction = dependentAction;

    }

    public SyncPrinterAction( int[] data, boolean dependent) {
        this.data = data;
        this.dependent = dependent;
    }

    public SyncPrinterAction( int[] data, SyncPrinterAction dependentAction, boolean dependent) {
        this.dependentAction = dependentAction;
        this.data = data;
        this.dependent = dependent;
    }

    @Override
    public void run() {
        synchronized (this) {

            for (int value : data) {

                try {
                    while(dependentAction.isDependent())
                        //System.out.println("\t\t"+Thread.currentThread().getName() + " :: Waithing for dependent action to complete");
                    wait(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                dependentAction.setDependent(true);

                System.out.println(Thread.currentThread().getName() + " :: " +value);
                dependent = false;
            }

        }

    }

    private void setDependent(boolean dependent) {
        this.dependent = dependent;

    }

    private boolean isDependent() {
        return dependent;
    }

}
于 2016-04-28T09:20:52.577 回答