Reg*_*ser 14 java multithreading synchronization
在下面的类中,方法getIt()  线程安全,为什么?
public class X { 
  private long myVar; 
  public void setIt(long  var){ 
    myVar = var; 
   }  
   public long getIt() { 
     return myVar; 
  } 
}
Phi*_*oss 22
它不是线程安全的.类型long和doubleJava中的变量被视为两个独立的32位变量.一个线程可以写入,并且当另一个线程读取两个半部分时写入一半的值.在这种情况下,读者会看到一个永远不会存在的值.
要使此线程安全,您可以声明myVar为volatile(Java 1.5或更高版本)或同时生成setIt和getIt synchronized.
请注意,即使myVar是32位,int您仍然可能遇到线程问题,其中一个线程可能正在读取另一个线程已更改的过期值.这可能是因为CPU已缓存该值.要解决此问题,您还需要声明myVar为volatile(Java 1.5或更高版本)或同时生成setIt和getIt synchronized.
值得注意的是,如果您getIt在后续setIt调用中使用结果,例如x.setIt(x.getIt() * 2),那么您可能希望synchronize跨越两个调用:
synchronized(x)
{
  x.setIt(x.getIt() * 2);
}
如果没有额外的同步,另一个线程可能会更改getIt和setIt调用之间的值,从而导致其他线程的值丢失.
这不是线程安全的.即使您的平台保证原子写入long,缺少synchronized使得一个线程可能调用setIt(),甚至在此调用完成后,另一个线程可以调用,getIt()并且此调用可能返回旧值myVar.
该synchronized关键字不仅仅是对一个块或方法的一个线程的独占访问.它还保证第二个线程被告知变量的变化.
因此,您必须将两种方法都标记为synchronized或将成员标记myVar为volatile.
有一个关于同步很好的解释在这里:
原子动作不能交错,因此可以使用它们而不必担心线程干扰.但是,这并不能消除所有同步原子操作的需要,因为仍然可能存在内存一致性错误.使用volatile变量可降低内存一致性错误的风险,因为对volatile变量的任何写入都会建立与之后读取同一变量的先发生关系.这意味着对volatile变量的更改始终对其他线程可见.更重要的是,它还意味着当线程读取volatile变量时,它不仅会看到volatile的最新更改,还会看到导致更改的代码的副作用.
不,这不对.至少,不在缺乏原子64位内存访问的平台上.
假设线程A调用setIt,将32位复制到后备值所在的内存中,然后在它可以复制其他32位之前进行抢占.
然后线程B调用getIt.
| 归档时间: | 
 | 
| 查看次数: | 1031 次 | 
| 最近记录: |