我有一个用例,我已经在一个小代码示例中复制了:
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()));
}
}
}
我有两个共享变量计数的线程,它定义为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后所看到的,Thread-1打印4。我的假设是Thread-1进入synchronized方法get并被thread-0的increment方法阻塞,一旦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());
答案 0 :(得分:4)
这是一种竞争条件。 JVM不保证将多少个周期用于任一线程。所以挥发性工作,因为你没有看到相同的数字显示两次。但是,在两个线程中执行命令的顺序并不像您预期的那样。它没有去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都可以递增一个易失整数,然后等待CyclicBarrier让它们继续