java中的并发循环

java中的并发循环,java,multithreading,concurrency,Java,Multithreading,Concurrency,我想运行两个共享一个方法的线程来打印一些东西。我希望将此作为输出: a b a b a b 第一个线程打印一个“a”,第二个线程打印一个“b”。我设法打印了一次,但我不能包含一个适当的循环来交换打印 我编写了以下代码来执行此操作: public void run() { while(i<10) { synchronized(this) { while (turn!=turn) { try {

我想运行两个共享一个方法的线程来打印一些东西。我希望将此作为输出:

a b a b a b 
第一个线程打印一个“a”,第二个线程打印一个“b”。我设法打印了一次,但我不能包含一个适当的循环来交换打印

我编写了以下代码来执行此操作:

public void run() {
    while(i<10) {
        synchronized(this) {
            while (turn!=turn) {
                try {
                    turn=!turn;
                    wait();
                    sleep(10);
                }
                catch(InterruptedException ie){}
            }

            printThreadOutput();
            turn=!turn;
            i++;
            notifyAll();
        }
    }
}
public void run(){
而
  • 在while之前让其中一个线程休眠5秒。它将明确哪个线程的顺序
  • while
    循环未执行,因为其条件始终为
    false
    。将内部
    while
    一起删除,您不需要它
  • 不需要
    turn
    变量。
    synchronize
    Thread.sleep(5)
    将使线程轮流
  • 捕获
    中断异常时,请至少放置一些
    println

  • 一个简单的解决方案是使用,它将执行所有所需的等待和通知操作:

    public class ThreadTest {
    
        private static final Lock lock = new ReentrantLock();
    
        public static final void main(String[] args) {
            Runnable aRun;
            Runnable bRun;
    
            aRun = new Runnable() {
                public void run() {
                    while (true) {
                        lock.lock();
                        System.out.println("a");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                        lock.unlock();
                    }
                }
            };
    
            bRun = new Runnable() {
                public void run() {
                    while (true) {
                        lock.lock();
                        System.out.println("b");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                        lock.unlock();
                    }
                }
            };
    
            Thread aThread = new Thread(aRun);
            Thread bThread = new Thread(bRun);
            aThread.start();
            bThread.start();
        }
    
    }
    
    如果不使用监视器,您可以这样做,但正如@noahz谦卑地指出的那样,它使用的是一种效率不高的方法

    public class ThreadTest {
    
        private static volatile Boolean isATurn = true;
    
        public static void main(String[] args) {
            Runnable aRun;
            Runnable bRun;
    
            aRun = new Runnable() {
                public void run() {
                    while (true) {
                        while (!isATurn) {
                        }
                        System.out.println("a");
                        isATurn = false;
                    }
                }
            };
    
            bRun = new Runnable() {
                public void run() {
                    while (true) {
                        while (isATurn) {
                        }
                        System.out.println("b");
                        isATurn = true;
                    }
                }
            };
    
            Thread aThread = new Thread(aRun);
            Thread bThread = new Thread(bRun);
            aThread.start();
            bThread.start();
        }
    
    }
    

    据我所知,这保证没有死锁,但如果其中一个线程没有终止,因为另一个线程正在等待,则可能会出现饥饿。但是,对于这样一个简单的示例来说,这不应该是一个问题。监视器也更倾向于使用轮询,但要稍微复杂一些。

    现在是凌晨3:30,我不想去哦,睡觉。 这就是我想到的:

    class TurnHolder {
    
        private volatile int currentTurn;
    
        public void setNextTurn() {
        this.currentTurn = currentTurn^1;
        }
    
        public int getCurrentTurn() {
        return currentTurn;
        }
    }
    
    class Printer implements Runnable {
    
        private String toPrint;
        private TurnHolder sharedResource;
        private int turn;
    
        Printer(String toPrint, TurnHolder sharedResource, int turn) {
        this.toPrint = toPrint;
        this.sharedResource = sharedResource;
        this.turn = turn;
        }
    
        @Override
        public void run() {
    
        while (true) {
            synchronized (sharedResource) {
            if (sharedResource.getCurrentTurn() != turn)
                try {
                sharedResource.wait();
                } catch (InterruptedException e) {
                e.printStackTrace();
                }
            System.out.println(toPrint);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            sharedResource.setNextTurn();
            sharedResource.notifyAll();
            }
        }
    
        }
    
    运行它的一种方法是:

    TurnHolder sharedResource = new TurnHolder();
    
    Printer printerA = new Printer("a", sharedResource, 0);
    Printer printerB = new Printer("b", sharedResource, 1);
    
    new Thread(printerA).start();
    new Thread(printerB).start();
    
    这样,你的
    sharedResource
    将保留该回合的记忆,并在其上进行同步,允许你在该回合中做你必须做的事情,然后你可以切换回合。
    线程。睡眠
    只是让你以很好的速度查看打印。
    System.out.println(toPrint);
    是您的
    printThreadOutput();


    附言:欢迎就如何改进代码提出建议。

    while(turn!=turn)
    synchronized
    应该解决非迂回代码中包含混合制表符和空格的缩进问题–这是一个坏主意。您应该确保一致使用制表符或空格。您发布的代码有什么问题?另外,
    while(turn!=turn)
    的计算结果仅为
    while(false)
    ,这意味着所有的代码都永远不会执行。啊,忙旋转锁。我也有你的代码的经验,这非常有用。“同步和线程。睡眠(5)将使线程轮流”。严格来说,这不是真的。大多数JVM在调用
    线程时都会执行上下文切换。sleep
    ,但不能保证在该线程睡眠时另一个线程会运行。如果要保证这种行为,您应该始终拥有一个控制变量。好吧!根据您的说明,它工作得很好。谢谢