2017-10-13 84 views
0

在进行多线程时,我一直在寻找线程安全性。我正在研究使用锁来使自定义数据结构线程安全。在java中自定义数据结构线程安全吗?

这是用于制作此自定义直方图线程安全的最合适的实现吗?

另外我是新来的。如果我想要帮助跟踪代码以找出它的作用,是否有我可以使用的标签?

直方图类(不安全)

public class Histogram 
{ 
    protected long[] bins; 
    protected int min, max, range; 
    protected int numBins; 

    public Histogram(int max, int min, int numBins) 
    { 
     this.max = max; 
     this.min = min; 
     this.numBins = numBins; 
     bins = new long[numBins]; 
     range = max - min + 1; 
    } 

    public void add(int num) 
    { 
     int bin = (int) Math.floor(((num - min) * 1.0/range) * numBins); 
     bins[bin]++; 
    } 

    public int absDifference(Histogram histogram) 
    { 
     int sum = 0; 
     if (histogram.min == min && histogram.max == max && histogram.numBins == numBins) 
      for (int i = 0; i < bins.length; i++) 
       sum += (int) Math.abs(bins[i] - histogram.bins[i]); 

     return sum; 
    } 

    @Override 
    public String toString() 
    { 
     String out = String.format("{Min: %d, Max: %d, # Bins: %d, Values: ", min, max, numBins); 
     for (int i = 0; i < bins.length; i++) 
      out += bins[i] + ", "; 

     out = out.substring(0, out.length() - 2); 
     out += "}"; 
     return out; 
    } 
} 

线程安全类的直方图

import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 


public class HistogramSafe extends Histogram 
{ 
    private Lock[] binLocks; 

    public HistogramSafe(int max, int min, int numBins) 
    { 
     super(max, min, numBins); 

     binLocks = new ReentrantLock[numBins]; 
     for (int i = 0; i < numBins; i++) 
      binLocks[i] = new ReentrantLock(); 
    } 

    @Override 
    public void add(int num) 
    { 
     int bin = (int) Math.floor(((num - min) * 1.0/range) * numBins); 

     binLocks[bin].lock(); 
     bins[bin]++; 
     binLocks[bin].unlock(); 
    } 
} 
+0

如果用户回答您的问题,请接受他的回答([接受答案:它是如何工作的?](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-工作))。如果不是,那么请说明还没有答案,这是StackOverflow的重要组成部分,非常感谢。 – Zabuza

回答

1

这要看情况。如果您的numBins(也minmax)可变不能改变,即你的数据结构是固定大小的,那么它应该是线程安全,允许不同的仓的平行修饰。


但如果numBins(或minmax)是可以修改的,然后它不是线程安全的了。正如您之前访问numBins那么这也是一个共享资源,并且它不在之内,相同的锁

线程可能会进入方法,读取numBins然后睡眠(由于线程调度程序)。现在另一个线程来执行完整的方法。旧线程继续并设置bins[bin]++,但过期值numBins

如果,例如,还提供了remove功能,那么这甚至有可能导致IndexOutOfBoundException以来的第一个线程可以读取尺寸10,然后其他线程减少大小5。当第一个线程继续时,它可能会尝试写入无效索引

1

为了确保一种方法是线程安全的,​​关键字可以提供帮助。另外任何不可变的数据结构都是主要是线程安全。

public synchronized void methodName(){} 

Zabuza说,这将阻止所有试图调用该方法的线程。

另一种方式保证线程安全是使synchronized块将采取作为参数上要进行锁定

public void methodName(){ 
    synchronized(object) { 
    ... 
    } 
} 
+3

'synchronized',在这种情况下,会阻塞所有线程的整个方法。 OP试图实现想要修改**不同bin的线程**可以继续。 – Zabuza

1

您应该调查使用的AtomicInteger为你的bin成员的对象。在你的例子中,线程安全问题是由于整数增加(读取,添加,写入)。 AtomicInteger操作是线程安全的,速度更快。

同步和锁定更适合保护复杂的数据结构。

0

我会从不同的角度来看待这个 - 不,在我看来,它不是线程安全的。为什么?因为你允许继承。当有人扩展这个类时,很多事情可能会出错 - 主要是覆盖add方法。