public class Test {
public static int num = 0;
public static void main(String[] args) {
new Thread(Test::printer, "t0").start();
new Thread(Test::printer, "t1").start();
new Thread(Test::printer, "t2").start();
}
public static void printer() {
synchronized (Test.class) {
while (num < 100) {
if (Thread.currentThread().getName().contains(String.valueOf(num % 3))) {
System.out.println(Thread.currentThread().getName() + ": " + num++);
}
Test.class.notifyAll();
try {
Test.class.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
Test.class.notifyAll();
}
}
}
我用jdk1.8运行下面的代码没有问题。它可以输出0到99。但是当我用jdk11运行代码时,它停在2或3。我用
jstack
检查线程状态,结果如下:
"Monitor Ctrl-Break" #21 daemon prio=5 os_prio=0 cpu=15.63ms elapsed=10.26s tid=0x000001ccc56cf800 nid=0x5424 runnable [0x000000a410efe000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0([email protected]/Native Method)
at java.net.SocketInputStream.socketRead([email protected]/SocketInputStream.java:115)
at java.net.SocketInputStream.read([email protected]/SocketInputStream.java:168)
at java.net.SocketInputStream.read([email protected]/SocketInputStream.java:140)
at sun.nio.cs.StreamDecoder.readBytes([email protected]/StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead([email protected]/StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read([email protected]/StreamDecoder.java:178)
- locked <0x00000007181038c8> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read([email protected]/InputStreamReader.java:181)
at java.io.BufferedReader.fill([email protected]/BufferedReader.java:161)
at java.io.BufferedReader.readLine([email protected]/BufferedReader.java:326)
- locked <0x00000007181038c8> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine([email protected]/BufferedReader.java:392)
at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:56)
"t0" #22 prio=5 os_prio=0 cpu=0.00ms elapsed=10.25s tid=0x000001ccc56d0000 nid=0x6560 in Object.wait() [0x000000a4110fe000]
java.lang.Thread.State: BLOCKED (on object monitor)
at java.lang.Object.wait([email protected]/Native Method)
- waiting on <0x0000000718113e10> (a java.lang.Class for com.chen.Test)
at java.lang.Object.wait([email protected]/Object.java:328)
at com.chen.Test.printer(Test.java:21)
- waiting to re-lock in wait() <0x0000000718113e10> (a java.lang.Class for com.chen.Test)
at com.chen.Test$$Lambda$14/0x0000000800066840.run(Unknown Source)
at java.lang.Thread.run([email protected]/Thread.java:834)
"t1" #23 prio=5 os_prio=0 cpu=3718.75ms elapsed=10.25s tid=0x000001ccc56d1000 nid=0x7b8 in Object.wait() [0x000000a4111ff000]
java.lang.Thread.State: BLOCKED (on object monitor)
at java.lang.Object.wait([email protected]/Native Method)
- waiting on <no object reference available>
at java.lang.Object.wait([email protected]/Object.java:328)
at com.chen.Test.printer(Test.java:21)
- waiting to re-lock in wait() <0x0000000718113e10> (a java.lang.Class for com.chen.Test)
at com.chen.Test$$Lambda$15/0x0000000800066c40.run(Unknown Source)
at java.lang.Thread.run([email protected]/Thread.java:834)
"t2" #24 prio=5 os_prio=0 cpu=4140.63ms elapsed=10.25s tid=0x000001ccc56d2000 nid=0x6620 in Object.wait() [0x000000a4112ff000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait([email protected]/Native Method)
- waiting on <no object reference available>
at java.lang.Object.wait([email protected]/Object.java:328)
at com.chen.Test.printer(Test.java:21)
- waiting to re-lock in wait() <0x0000000718113e10> (a java.lang.Class for com.chen.Test)
at com.chen.Test$$Lambda$16/0x0000000800066040.run(Unknown Source)
at java.lang.Thread.run([email protected]/Thread.java:834)
t0 和 t1 都被阻塞了,但是他们都没有得到 cpu,所以谁能告诉我为什么我得到这个结果?
总结你的代码做什么
你创建了 3 个线程并让它们并行运行
static printer()
。在 synchronized
循环中,如果当前线程负责这样做,则当前线程会递增一个数字 (%3
)。仍在循环内,让 JVM 选择其他线程之一继续,同时将当前线程置于等待状态。
会发生什么
notifyAll():
有关线程可以成为监视器所有者的方式的描述,请参阅通知方法。
通知():
如果有任何线程正在等待这个对象,则选择其中一个被唤醒。选择是任意的,由实现自行决定。
发生的情况是监视器获取仅在 3 个线程中的 2 个之间切换,而恰好负责递增当前值的第三个线程没有出现。
哦,您需要使变量
volatile
以确保所有线程读取最新更新的值。我认为这可能已经是观察到的行为的正当理由。
当我从 Java 8 更新到 11 时。我不得不添加额外的依赖项并从 pom.xml 中排除一些现有的依赖项。 Java 11 有很多 java 8 中没有的 jar。希望这有帮助:)