我正在关注here的例子
我已将processCommand修改为 –
private void processCommand() throws InterruptedException {
this.command = "xyz";
}
完整代码 –
import java.util.logging.Level;
import java.util.logging.Logger;
public class WorkerThread implements Runnable {
private String command;
public WorkerThread(String s) {
this.command = s;
}
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(WorkerThread.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(Thread.currentThread().getName() + " Commad at start :" + command);
try {
processCommand();
} catch (InterruptedException ex) {
}
System.out.println(Thread.currentThread().getName() + " Command after processCommand : " + command);
}
private void processCommand() throws InterruptedException {
this.command = "xyz";
}
}
现在,我希望看到同步问题,对吗?基本上,什么时候
System.out.println(Thread.currentThread().getName()+' Start. Command = '+command);
执行后,它可以获取值xyz,对吗?但我从来没有看到它.我在Thread.Sleep中尝试了各种值.
那么是什么让this.command =“xyz”;语句线程安全在这种情况下?
我以这种方式开始线程 –
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread("" + i);
executor.execute(worker);
}
解决方法:
UPDATE
它仍然不完全是整个程序的样子……但基于我的想法,我看不出它不是线程安全的任何一点.
分配命令有两个点,读取值有两个点.
>主线程在构造函数中指定命令.
>第二个线程在调用processCommand之前在run()中读取命令.
>第二个线程在processCommand中分配命令
>第二个线程在调用processCommand后在run()中读取命令.
最后三个事件发生在同一个线程上,因此不需要同步.第一个和第二个事件发生在不同的线程上,但在那一点上主线程和工作线程之间应该存在“先发生”关系.
>如果主线程要启动()第二个线程,那将提供之前发生的事情. (JLS这样说.)
>但实际上我们正在使用ThreadPoolExecutor.execute(Runnable)进行移交,并根据javadoc for Executor:
Memory consistency effects: Actions in a thread prior to submitting a Runnable object to an Executor happen-before its execution begins, perhaps in another thread.
总之,所有感兴趣的4个事件都是正确同步的,并且没有涉及命令的竞争条件.
但是,即使这不是线程安全的,您也很难证明非线程安全的行为.
>无法证明它的主要原因是实际的非安全性是由Java内存模型引起的.如果存在同步点或某些事情以确定“之前发生”,则只需将命令变量的更改刷新到主存储器.但无论如何它们都可以刷新……而且它们通常都是……特别是如果有足够长的时间间隔或系统调用导致上下文切换.在这种情况下,你有两个.
>第二个原因是System.err和System.out对象在内部同步,如果您不小心调用它们,则可以消除您尝试演示的线程安全问题.
这是涉及非同步访问共享变量的线程安全问题的“问题”.实际的比赛条件通常涉及非常小的时间窗口;即两个事件需要在几个时钟周期内发生(当然小于一微秒)才能引起比赛.这可能很少发生,这就是为什么涉及竞争条件的问题通常难以重现的原因.