我试图同步到两个线程,一个打印“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)
答案 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
的价值是什么,都会打印出来。