多线程系统的Java不可变对象。我做错了什么?
我是个不可变对象的傻瓜。我的想法是,它们在多线程环境中很有用,而且从定义上讲是线程安全的 但是下面的代码似乎正好相反多线程系统的Java不可变对象。我做错了什么?,java,multithreading,concurrency,immutability,Java,Multithreading,Concurrency,Immutability,我是个不可变对象的傻瓜。我的想法是,它们在多线程环境中很有用,而且从定义上讲是线程安全的 但是下面的代码似乎正好相反 public class ImmutableTest { volatile ImmutableObject obj; public static void main(String[] args) throws InterruptedException { new ImmutableTest().execute(); } pri
public class ImmutableTest {
volatile ImmutableObject obj;
public static void main(String[] args) throws InterruptedException {
new ImmutableTest().execute();
}
private void execute() throws InterruptedException
{
obj = new ImmutableObject(0);
ExecutorService exec = Executors.newFixedThreadPool(50);
for(int i = 0; i < 50; i++){
exec.execute(new ImmutableRunnable(this));
}
Thread.sleep(5000);
exec.shutdown();
obj.print();
}
}
public class ImmutableRunnable implements Runnable {
ImmutableTest test;
ImmutableRunnable(ImmutableTest immutableTest) {
this.test = immutableTest;
}
public void run() {
this.test.obj = new ImmutableObject(this.test.obj.getValue());
}
}
public final class ImmutableObject {
private int n;
public ImmutableObject(int newValue) {
this.n = newValue;
if(Math.random() > .5){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void print() {
System.out.println(n);
}
public int getValue() {
return n;
}
}
公共类不可变测试{
易失性不可变对象obj;
公共静态void main(字符串[]args)引发InterruptedException{
新建ImmutableTest().execute();
}
private void execute()引发InterruptedException
{
obj=新的不可变对象(0);
ExecutorService exec=Executors.newFixedThreadPool(50);
对于(int i=0;i<50;i++){
exec.execute(新的Immutablerunable(this));
}
睡眠(5000);
exec.shutdown();
obj.print();
}
}
公共类ImmutableRunnable实现Runnable{
免疫试验;
Immutablerunable(ImmutableTest ImmutableTest){
this.test=不可变测试;
}
公开募捐{
this.test.obj=新的ImmutableObject(this.test.obj.getValue());
}
}
公共最终类ImmutableObject{
私人int n;
公共不可变对象(int newValue){
这个.n=新值;
if(Math.random()>.5){
试一试{
睡眠(100);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
公开作废印刷品(){
系统输出println(n);
}
public int getValue(){
返回n;
}
}
在线程安全的环境中,我希望结果是50。但事实并非如此。如果从ImmutableObject构造函数中取消随机睡眠,则得到50
那么结论是什么?不可变对象是线程安全的“如果构造函数足够快”?或者(更可能)我误解了什么
对不起,我没有正确地解释我的疑问。这不是一个同步问题,我学习了如何同步方法和使用锁。这个问题涉及不可变对象及其与多线程的关系。我到处都读到一个不可变的对象是线程安全的,因此它可以在线程之间毫无畏惧地共享。但我觉得这根本不是真的!!!
所以你能不能给我举个例子,一个不可变的对象在不同的线程之间共享,它的使用不需要同步?
谢谢各位。你们误解了什么 不可变对象允许您安全地共享对象并读取任何方法/字段,而无需使用锁 在这种情况下,您需要依赖可变的
obj
引用以某种方式进行同步-事实并非如此
不变性只是一个不能修改的对象。修改状态后,需要执行一些同步,以确保所需的实际发生。例如,整个“通过读取obj设置obj”调用需要是独占的,并且以串行方式发生。您误解了某些内容 不可变对象允许您安全地共享对象并读取任何方法/字段,而无需使用锁 在这种情况下,您需要依赖可变的
obj
引用以某种方式进行同步-事实并非如此
不变性只是一个不能修改的对象。修改状态后,需要执行一些同步,以确保所需的实际发生。例如,整个“通过读取obj设置obj”调用需要是独占的,并且以串行方式发生。Immutablerunable.run()不是线程安全的:
- 它读取obj中的值
- 它创建一个新的不可变对象
- 它更新了obj
- 它读取obj中的值
- 它创建一个新的不可变对象
- 它更新了obj
解决这个问题的最简单方法是在ImmutableTest上同步。正如Yann Ramin所说,不可变对象允许您安全地共享和使用对象,而无需使用锁
但是,您在这里测试的是写入类
Immutabletest
的obj
字段的线程安全性<代码>不可变测试不是不可变的,因此不是线程安全的。正如Yann Ramin所说,不可变对象允许您安全地共享和使用对象,而无需使用锁
但是,您在这里测试的是写入类Immutabletest
的obj
字段的线程安全性<代码>不可变测试不是不可变的,因此不是线程安全的
AtomicReference obj = new AtomicReference();// was volatile obj
... change obj access in execute to match
... replace run method with following:
ImmutableObject curr;
do{
curr = this.test.obj.get();
}while(!this.test.obj.compareAndSet(curr, new ImmutableObject(curr.getValue()+1)));