微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

java – 在线程之间共享数据库

我有一个应用程序是多线程和工作正常.然而,它遇到了锁争用问题(通过快照查看 java堆栈并查看等待的内容).

每个线程都从列表中消除对象,并拒绝每个线程或将其放入Bin.

箱子最初是空的,因为每个都可以是昂贵的(并且有可能很多它们).

导致争用的代码大致如下:

public void addToBin(Bin[] bins,Item item) {
   Bin bin;
   int bin_index = item.bin_index
   synchronized(bins) {
      bin = bins[bin_index];
      if(bin==null) {
        bin = new Bin();
        bins[bin_index] = bin;
      }
   }
   synchronized(bin) {
     bin.add(item);
   }
}

它是在瓶颈阵列上的同步,这是瓶颈.

有一位同事向我建议使用双重锁定来解决这个问题,但是我们不确定它会涉及什么来使其安全.建议的解决方案如下所示:

public void addToBin(Bin[] bins,Item item) {
   int bin_index = item.bin_index
   Bin bin = bins[bin_index];

   if(bin==null) {
     synchronized(bins) {
        bin = bins[bin_index];
        if(bin==null) {
          bin = new Bin();
          bins[bin_index] = bin;
        }
     }
   }

   synchronized(bin) {
     bin.add(item);
   }
}

这是安全的还是/或者有更好/更安全/更惯用的方式来做到这一点吗?

解决方法

如Malt的答案所述,Java已经提供了许多无锁数据结构和概念,可以用来解决这个问题.我想使用atomicreferenceArray添加更详细的示例:

假设bins是一个atomicreferenceArray,以下代码执行一个空闲的空闲更新,以防空条目:

Bin bin = bins.get(index);
while (bin == null) {
    bin = new Bin();
    if (!bins.compareAndSet(index,null,bin)) {
        // some other thread already set the bin in the meantime
        bin = bins.get(index);
    }
}
// use bin as usual

自从Java 8以来,有一个更优雅的解决方案:

Bin bin = bins.updateAndGet(index,oldBin -> oldBin == null ? new Bin() : oldBin);
// use bin as usual

节点:由于事实上,即使值不改变,updateAndGet将始终更新数组,Java 8版本仍然是非阻塞状态.这可能或可能不可忽略,取决于整个bin更新操作的总体成本.

一个非常优雅的策略可能是将新建的Bin实例的整个bin数组预先填满,然后将数组移交给工作线程.由于线程不必修改阵列,这将减少与Bin对象本身同步的需要.通过使用Arrays.parallelSetAll(从Java 8开始)可以轻松完成数组填充多线程:

Arrays.parallelSetAll(bins,i -> new Bin());

更新2:如果这是一个选项取决于您的算法的预期输出:最终将数组填充完整,密集或只是稀疏? (在第一种情况下,预先填充是可取的,在第二种情况下,它依赖于这种情况,在后一种情况下,这可能是一个坏主意).

更新1:不要使用双重检查锁定!这不安全!这里的问题是可见性,而不是atomicitiy.在您的情况下,读取线程可能会部分构造(因此损坏)Bin实例.详见http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html.

原文地址:https://www.jb51.cc/java/122823.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐