Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在线程之间共享对象以证明它不是线程安全的?_Java_Multithreading - Fatal编程技术网

Java 如何在线程之间共享对象以证明它不是线程安全的?

Java 如何在线程之间共享对象以证明它不是线程安全的?,java,multithreading,Java,Multithreading,MutableInteger不被认为是线程安全类,因为当从不同线程调用时,它可能会返回过时的值 class MutableInteger{ private int value; public int get(){ return value; } public void set(int value){ this.value=value; } } 这是我的线程实现:-有一个主线程(main方法)并从中调用MyThread

MutableInteger不被认为是线程安全类,因为当从不同线程调用时,它可能会返回过时的值

class MutableInteger{
    private int value;

    public int get(){
       return value;
    }

    public void set(int value){
       this.value=value;
    }   
}
这是我的线程实现:-有一个主线程(main方法)并从中调用MyThread

class MyThread extends Thread{
    private int num;

    public void set(int num){
      this.num=num;
    }

    public void run(){
      MutableInteger mi=new MutableInteger();
      mi.set(num);
      System.out.println("Mythread "+mi.get());
    }
}

class MutableIntegerTest{
    public static void main(String[] args){
    MyThread t1=new MyThread();
    t1.set(10);     
    t1.start();
    MutableInteger mi=new MutableInteger();
    mi.set(99);
    System.out.println("Main thread" +mi.get());
    }
   }
这就是我未能理解的。对于访问状态变量
value
我们需要使用类
MutableInteger
的getter和setter方法,因此对于每次访问,我们都需要实例化
MutableInteger
类。现在根据理论,每个对象都有自己的实例变量副本。在我的实现中,两个线程仅通过
MutableInteger
实例访问
变量。在我的例子中,
在线程之间不共享,从而使我的MutableInteger线程安全

我应该如何使线程共享
?我是否应该公开该对象,以便在两个线程中使用相同的对象?但是这不会将对象公开给所有可用的类和线程吗


我做错了什么吗?

如果您想测试
可变整数
以亲眼看到它不是线程安全的,您必须在线程之间共享一个对象。如果每个线程都创建了自己的instancef
MutableInteger
,那么正如您所注意到的,您实际上并没有测试这个特定的东西,因为它只被创建它的单个线程访问

因此,您需要创建一个实例,并让两个线程都使用它。例如:

可运行对象(最好使用扩展
线程的类):


现在,如果mutableInteger是线程安全的,那么您希望结果总是打印109000。但当然不会。每次运行时,它可能会打印不同的数字,有时甚至会为不同的线程打印不同的数字。

您当前的代码是线程安全的,但一般来说,您的类不是线程安全的。在
t1.start()
之前使用
t1.set()
是安全的,因为线程启动发生在edge之前(从启动的线程内部,您可以看到在
thread.start()
调用之前启动线程中发生的所有事件)。但是,如果在线程启动后调用
t1.set()
,则不能保证线程会看到该新值

对于
MutableInteger
也一样。目前,线程之间不共享
MutableInteger
实例,因此它们工作正常。但是,如果您共享,则不能保证更改是可见的。例如,考虑< <代码>运行()>代码>方法:

public void run(){
  MutableInteger mi=new MutableInteger();
  mi.set(num);
  System.out.println("Mythread "+mi.get());
}
目前,JIT编译器可以理解
MutableInteger
对象没有任何副作用,并对其对象进行优化,从而有效地将您的方法转换为:

public void run(){
  System.out.println("Mythread "+num);
}

即使没有JIT编译器优化,仍然存在内存可见性问题(可以将
MutableInteger
对象缓存在CPU核心一级缓存中,其他CPU核心将看不到更新的值)以及CPU指令重新排序。因此,如果没有
volatile
关键字,就不能保证另一个线程会看到更改。添加
volatile
关键字可以有效地将您的
MutableInteger
转换为现有的
AtomicInteger
(内部有一个int-volatile字段,还有更方便的方法以及setter和getter)。

反对意见

我认为
MutableInteger
类是线程安全的

当我声称一个类是线程安全的时,我的意思是,不同线程对其方法的重叠调用不会导致该类或该类的实例违反其API约定

MutableInteger
的API契约是什么

OP没有说明,但是任何一个合理的程序员都可以看到它的功能

我认为只要get()返回初始值0或之前设置的某个值();只要get()在同一个线程
t
中返回了一个较新的值之后,再也不会返回线程
t
中较旧的值,那么我认为该类的行为是合理的

保证方法调用之间的关系之前发生的任何类型的Java库类通常在其文档中详细说明这些保证。例如,从
java.util.concurrent.BlockingQueue
接口的javadoc:

…将对象放入
BlockingQueue
之前线程中的操作发生在另一个线程中从
BlockingQueue
访问或移除该元素之后的操作之前


我没有看到任何关于
MutableInteger
类的声明,因此,如果它的行为像普通int而不是
volatile
int,我就不会称它为“坏的”。

你有什么问题?除了
MyThread.num
之外,没有其他共享数据,只有在线程尚未启动时才会设置。或者更确切地说:你想实现什么?考虑AtomicInteger。那么我应该如何从1多个线程访问同一个实例。我应该将实例公开还是将实例从一个线程传递到另一个线程?给定MutableInteger类,我只想知道如何为它编写线程类…\u我只想知道如何为它编写线程类。这是什么意思?“thread class for it”会做什么?这并没有回答“如何在线程之间共享变量”的问题,您只展示了如何获取与线程相关的错误,因此您的答案是无用的。@Krzysztofcichhoki它实际上是这样做的-特别是考虑到OP解释他实际询问的内容的评论。请注意,此测试的编写方式
public void run(){
  MutableInteger mi=new MutableInteger();
  mi.set(num);
  System.out.println("Mythread "+mi.get());
}
public void run(){
  System.out.println("Mythread "+num);
}