关于java线程的具体问题&x2B;同步 我知道这个问题听起来很疯狂,但是考虑下面的java片段:

关于java线程的具体问题&x2B;同步 我知道这个问题听起来很疯狂,但是考虑下面的java片段:,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,第一部分: class Consumer implements Runnable{ private boolean shouldTerminate = false public void run() { while( !shouldTerminate ){ //consume and perform some operation. } } public void termin

第一部分:

 class Consumer implements Runnable{
      private boolean shouldTerminate = false
      public void run() {
          while( !shouldTerminate ){
               //consume and perform some operation.
          }
      }

      public void terminate(){
        this.shouldTerminate = true;
      }
    }
所以,第一个问题是,我是否需要在shouldTerminate布尔上进行同步?如果是,为什么?我不介意在一个或两个循环(循环=1循环执行)中丢失设置为true的标志。第二,布尔变量是否会处于不一致的状态?(除true或false之外的任何内容)

问题第二部分:

class Cache<K,V> {

  private Map<K, V> cache = new HashMap<K, V>();

  public V getValue(K key) {
     if ( !cache.containsKey(key) ) {
       synchronized(this.cache){
          V value = loadValue(key)
          cache.put(key, value);
       }  
      } 
     return cache.get(key);
  }
}
类缓存{
私有映射缓存=新的HashMap();
公共V getValue(K键){
如果(!cache.containsKey(键)){
已同步(此.cache){
V值=负载值(键)
cache.put(键、值);
}  
} 
返回cache.get(key);
}
}

是否应该同步访问整个地图?是否存在两个线程尝试运行此方法的可能性,一个“编写线程”正在将值存储到映射的过程中,另一个“读取器线程”同时调用“contains”方法。这会导致JVM崩溃吗?(我不介意覆盖映射中的值——如果两个writer线程试图同时加载)

除非对变量进行同步,或者将变量标记为volatile,否则无法保证单独线程的对象视图能够协调。引用

这方面的主要警告是,似乎串行语义不会阻止不同线程拥有不同的数据视图

实际上,只要两个线程在某个时间在某个锁上同步,就会看到变量的更新

我想知道为什么您不想将变量
标记为volatile

  • 同步
    应终止
    :请参阅 迪卢姆的回答
  • 你的布尔值会 永远不要处于不一致的状态
  • 如果有 线程正在调用
    cache.containsKey(键)
    while 另一个线程正在调用
    cache.put(key,value)
    JVM将 放大(通过抛出ConcurrentModificationException) 如果
    put
    调用导致映射,则可能会发生不好的情况 这会增长,但通常会起作用(比失败更糟)

  • 这两个代码示例都破坏了并发性

    第一个线程至少需要标记为
    volatile
    的字段,否则另一个线程可能永远看不到变量被更改(它可能将其值存储在CPU缓存或寄存器中,而不检查内存中的值是否已更改)


    第二个更坏,因为
    HashMap
    的内部不是线程安全的,它不仅仅是一个值,而是一个复杂的数据结构——从多个线程使用它会产生完全不可预测的结果。一般规则是读取和写入共享状态必须同步。您还可以使用
    ConcurrentHashMap
    来获得更好的性能。

    并不是说JVM会像这样“爆炸”。但这两种情况都不正确地同步,因此结果将是不可预测的。底线是,如果您以特定的方式进行同步,JVM被设计成以特定的方式运行;如果同步不正确,就失去了这种保证


    人们认为他们已经找到了可以忽略某些同步的原因,或者在不知不觉中忽略了必要的同步,但没有立即出现的明显问题,这种情况并不少见。但是,如果同步不充分,您的程序可能会在一个环境中工作正常,只有在特定因素发生变化时(例如,移动到具有更多CPU的机器,或对JVM进行更新以添加特定优化),才会出现问题。

    3。JVM会爆炸吗?ConcurrentModificationException仅在快速失败迭代器中发生。如果映射本身没有同步,您可能不会得到异常——最好的情况是数据不一致,最坏的情况是无限循环。另一方面,如果使用Collections.synchronizedMap(),则只会得到两个LoadValue/puts。这取决于需求。我倾向于同意最后一条评论——JVM“爆炸”,我认为提问者可能想到了比ConcurrentModificationException更糟糕的事情。@Peter:你说得对。我有点草率地发布了那篇文章。
    ConcurrentModificationException
    仅由HashMap的默认集合视图迭代器引发。是的,我所说的JVM崩溃==JVM由于内存损坏而崩溃等。。(这在C/C++程序中很容易发生)不用担心,我绝对同意“比失败更糟糕”:-)非常务实的答案。你的目标是对的。我拼命地试图避免同步以提高性能。实际上,标记一个变量volatile将实现与在对象上同步并读取“shouldTerminate”标志相同的效果。我想抄近路……不,同步比volatile有更广泛的含义。引用:“对volatile字段的写入发生在对同一volatile的每次后续读取之前”