java线程同步-这应该是';我不工作,但它是:)-

java线程同步-这应该是';我不工作,但它是:)-,java,multithreading,thread-safety,threadpool,Java,Multithreading,Thread Safety,Threadpool,我在下面举几个例子 我已将processCommand修改为- private void processCommand() throws InterruptedException { this.command = "xyz"; } 完整代码- import java.util.logging.Level; import java.util.logging.Logger; public class WorkerThread implements Runnable {

我在下面举几个例子

我已将
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中尝试了各种值

那么,是什么使得
这个.command=“xyz”语句是线程安全的吗

我是这样开始的-

ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
    Runnable worker = new WorkerThread("" + i);
    executor.execute(worker);
}
ExecutorService executor=Executors.newFixedThreadPool(5);
对于(int i=0;i<10;i++){
Runnable worker=新WorkerThread(“+i”);
执行人,执行人(工人);
}

在这里看不到竞争条件的原因是

Runnable worker = new WorkerThread('' + i);
竞争条件涉及共享资源。另一方面,您的所有工作线程都在更改自己的私有成员
命令
。要诱导一种竞赛条件,你需要做如下的事情

for (int i = 0; i < 10; i++) {
  Runnable worker = new WorkerThread('' + 0);    
  executor.execute(worker);
  worker.setCommand('' + i);
}
for(int i=0;i<10;i++){
Runnable worker=新的WorkerThread(“”+0);
执行人,执行人(工人);
worker.setCommand(“”+i);
}
现在,当工作人员尝试访问
命令
字段时,可能会得到过时的
0
值或
i
值。

更新

它仍然不完全是完整程序的样子。。。但根据我的想法,我看不出有任何一点不是线程安全的

有两个点分配
命令
,两个点读取值

  • 主线程在构造函数中分配
    命令
  • 在调用
    processCommand
    之前,第二个线程在
    run()
    中读取
    command
  • 第二个线程在
    processCommand
  • 调用
    processCommand
    后,第二个线程在
    run()
    中读取
    command
  • 最后三个事件发生在同一个线程上,因此不需要同步。第一个和第二个事件发生在不同的线程上,但此时主线程和工作线程之间应该存在“发生在”关系

    • 如果主线程是
      start()
      第二个线程,那么这将提供“在之前发生”的功能。(联合联络小组如是说。)

    • 但实际上,我们正在使用
      ThreadPoolExecutor.execute(Runnable)
      进行移交,并且根据for
      Executor

      内存一致性影响:在将可运行对象提交给执行器之前,线程中的操作发生在其执行开始之前,可能发生在另一个线程中

    总之,所有4个感兴趣的事件都已正确同步,并且没有涉及
    命令的竞争条件


    然而,即使这不是线程安全的,您也很难证明这种非线程安全的行为

    • 您无法演示它的主要原因是,实际的不安全性是由Java内存模型造成的。只有在存在同步点或建立“之前发生”的东西时,才需要将对
      命令的更改刷新到主存。但无论如何,它们都可以被冲掉。。。他们通常是。。。特别是当有足够长的时间间隔,或者系统调用导致上下文切换时。在这种情况下,两者都有

    • 第二个原因是
      System.err
      System.out
      对象是内部同步的,如果您不注意调用它们的方式,可以消除您试图演示的线程安全问题



    这就是线程安全问题的“关键”,涉及对共享变量的非同步访问。实际的比赛条件通常涉及非常小的时间窗口;i、 e.需要在几个时钟周期内发生的两个事件(当然不到一微秒)才能引起注意。这很可能很少发生,这就是为什么涉及竞争条件的问题通常很难重现的原因。

    向我们展示您的完整代码。是什么让您认为这是线程安全的?您的代码在
    命令
    变量上没有同步,并且如果多个线程正在访问
    命令
    ,它也不能保证该命令的值。仅仅因为你的代码没有抛出错误,并不意味着它是正确的或安全的:)@greedyfoddha-没错-我不认为它是线程安全的,但我的实验表明它是。在本例中,我如何诱导竞争条件?@user375868启动多个线程,并尝试修改
    命令
    @tarrsalah,我已经在这样做了。@assylias是的,即使是静态也会诱导竞争条件。多线程代码的编写非常简单!:)不,
    static
    没有帮助,因为字段没有可识别的正确值。使用
    static
    只能表明,撇开可见性问题不谈,线程交错发生在主线程和辅助线程之间。@TimBender代码很好。OP实际上是在测试一个发布的示例,但替换了问题中发布的流程命令。很可能,这就是为什么很难理解它是如何为您引入竞争条件的。为了声明存在并发错误,您需要某种方法来解释字段的值应该是什么。在您发布的示例代码中,这是不可能的,因为您在紧循环中修改相同的状态,同时让其他线程排队执行睡眠一秒钟。现在,您可以合理地认为该值应该始终为
    9
    ,因为循环可能在CPU交换到另一个线程之前完成。然而,这并不能保证。一个合理的结果可能是CPU只在时间片结束之前运行迭代0-4