我有一个用例,我已在一个小代码示例中复制了它:
package com.learning.thread;
public class ThreadInterupt {
public volatile int count;
public synchronized int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public synchronized void increment(){
count++;
}
public static void main(String[] args) throws InterruptedException {
ThreadInterupt local = new ThreadInterupt();
Thread firstThread = new Thread( new myThread(local));
Thread secondThread = new Thread( new myThread(local));
firstThread.start();
secondThread.start();
Thread.sleep(10);
firstThread.interrupt();
secondThread.interrupt();
}
}
class myThread implements Runnable{
static void threadMessage(String message) {
String threadName =
Thread.currentThread().getName();
System.out.format("%s: %s%n",
threadName,
message);
}
ThreadInterupt global;
public myThread(ThreadInterupt local){
global = local;
}
@Override
public void run() {
// TODO Auto-generated method stub
int i=0;
while(i<5){
if(Thread.interrupted()){
threadMessage("Got Killed");
break;
}
i++;
global.increment();
threadMessage(String.valueOf(global.getCount()));
}
}
}
我有两个线程共享一个变量 count ,该变量被定义为 volatile 。我在 ThreadInterupt 类中有两个方法,我在其中递增并获取 count 变量,两者都定义了 synchronized 。我的问题是,虽然我希望第二个线程能够正确获取递增值,但它却无法做到这一点。我也在添加输出。
Thread-0: 1
Thread-1: 2
Thread-0: 3
Thread-0: 5
Thread-0: 6
Thread-0: 7
Thread-1: 4
Thread-1: 8
Thread-1: 9
Thread-1: 10
正如您所见,线程 0 打印 7 后,线程 1 打印 4 。我这里的假设是 Thread-1 进入同步方法 get 并被 thread-0 的增量方法阻塞,一旦 thread-0 完成,它就会打印出 get 。我对此不太相信。有人可以帮忙吗?
//按照 codeBencher 的建议进行编辑,
这可能是因为延迟。当我向 ThreadInterupt 类添加同步打印方法时,效果很好。
public synchronized void print(String threadName){
System.out.println(threadName+String.valueOf(count));
}
并在run方法中
global.increment();
global.print(Thread.currentThread().getName());
最佳答案
这是一个竞争条件。 JVM 不会保证有多少个周期专用于任一线程。因此, volatile 起作用了,因为您不会看到相同的数字显示两次。但是跨两个线程执行命令的顺序并不像您预期的那样。它没有让 t-1 执行命令,现在 t-2 执行命令,现在再次执行 t-1,现在执行 t-2。相反,它可能会执行 t-1、t-1、t-1、t-2、t-1、t-1、t-2、t-2、t-2、t-2、t-2。 ...等等等等。要强制它按顺序进入 t-1、t-2、t-1、t-2..,您必须使用 concurrent package 中的类来使用其他技术。 .
例如,一种常见的技术是使用 ConcurrentLatch 或 Future 来等待一个或多个其他线程完成。 CyclicBarrier 是一个非常酷的系统,可以用于像这样的倒计时(或向上计数)系统。 ,其中 t-1 和 t-2 可以分别递增一个 volatile 整数,然后等待 CyclicBarrier 让它们继续。
关于Java线程一致性问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31667471/