试图同步两个线程

时间:2016-10-24 07:00:27

标签: java multithreading synchronized

我试图同步到两个线程,一个打印“ping”和另一个打印“pong”,打印类似“乒乓乒乓乒乓......”我编写了以下程序来实现这一点,但是不能得到预期的结果。我想知道我犯了什么错误。互联网上提供相同的解决方案,但我认为我应该自己尝试一下,然后才能找到现成的答案。

class MyThread implements Runnable{
  String val = null;
  MyThread(String val) {
      this.val = val;
  }

    public void run() {
        while(true){
            PingPong.pintMessage(val);
        }
    }
}

public class PingPong {
   static Integer turn = 1;

   public static void main(String args []) {
       Thread t1 = new Thread(new MyThread("ping"));
       Thread t2 = new Thread(new MyThread("pong"));
       t1.start();
       t2.start();

   }
   public static void pintMessage(String msg) {
       synchronized (turn) {
         if(turn==1) {
             System.out.println(Thread.currentThread().getName()+" "+msg);
             turn=2;
         }
         else {
             System.out.println(Thread.currentThread().getName()+" "+msg);
             turn = 1;
         }
    }
   }
}

输出:

Thread-0 ping
Thread-1 pong
Thread-1 pong
Thread-1 pong
Thread-0 ping
Thread-0 ping
Thread-0 ping
Thread-1 pong
Thread-1 pong
Thread-1 pong
Thread-0 ping
Thread-0 ping
Thread-0 ping
Thread-1 pong
Thread-1 pong
Thread-1 pong
Thread-0 ping
Thread-0 ping
Thread-0 ping
Thread-1 pong
Thread-1 pong
Thread-1 pong
Thread-0 ping
Thread-0 ping
Thread-0 ping
Thread-1 pong
Thread-1 pong
Thread-1 pong
Thread-0 ping
Thread-0 ping
Thread-0 ping
Thread-1 pong

请告知我在这里犯的根本错误,以及是否有更好的方法来实现相同的行为。谢谢!!

进行建议更改后:我尝试使用wait / notify进行线程通信,但获取了IllegalMonitorStateException。我想我已经在我获取锁定的对象上使用了wait / notify(在同步上下文中使用了wait / notify)。请帮助我理解这个概念的微妙之处。 Thnaks!

class MyThread implements Runnable{
    String val = null;

    MyThread(String val) {
        this.val = val;
    }

    public void run() {
        while(true){
            try {
                PingPong.printMessage(val);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}

public class PingPong {
    static Integer turn = 1;

    public static void main(String args []) {
        Thread t1 = new Thread(new MyThread("ping"));
        Thread t2 = new Thread(new MyThread("pong"));
        t1.start();
        t2.start();
    }
    public static void printMessage(String msg) throws InterruptedException {
        synchronized (turn) {
            if(turn==1) {
                System.out.println(Thread.currentThread().getName()+" "+msg);
                turn=2;
            }
            else {
                System.out.println(Thread.currentThread().getName()+" "+msg);
                turn = 1;
            }
            turn.notifyAll();
            turn.wait();
        }
    }
}

Output :
Thread-0 ping
Exception in thread "Thread-0" Thread-1 pong
java.lang.IllegalMonitorStateException
    at java.lang.Object.notifyAll(Native Method)
    at PingPong.printMessage(PingPong.java:40)
    at MyThread.run(PingPong.java:12)
    at java.lang.Thread.run(Unknown Source)

2 个答案:

答案 0 :(得分:3)

你有synchonized错误的概念。

JVM确保只有在执行 synchronized 块的进程上才会进行,但它不会控制进入进程,这意味着它只按照尝试调用的顺序处理调用块。

在您的情况下:每个线程都有机会在JVM将其设置为后台之前多次执行循环,以便执行另一个线程。

如果您想确保特定订单,则必须使用wait()notify() / notifyAll(): ([编辑]:此代码可能无法正常工作(未经测试),只是为了演示原理...)

class MyThread implements Runnable{
  private Object other;
  public void setOther (MyThread other){
    this.other = other;

  }
  //no changes
       while(true){
            PingPong.pintMessage(val);
            notifyAll();
            other.wait();
        }

}

public static void pintMessage(String msg) {
    synchronized (turn) {
     // no changes
      // MyThread.semaphore.notifyAll();
 }
}    

请参阅此处了解mor信息https://docs.oracle.com/javase/tutorial/essential/concurrency/

答案 1 :(得分:0)

pintMessage turn中,无论iOS10的价值是什么,都会打印出来。