我有一个在多线程应用程序中使用的 Java 类。并发访问的可能性很大。多个并发读取操作不应阻塞,因此我使用读写锁。

class Example {
    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private int i;
    private boolean b;

    public int getI() {
      lock.readLock().lock();
      final int tmp = i;
      lock.readLock().unlock(),
      return tmp;
    }

    public void setI( final int i ) {
      lock.writeLock().lock();
      this.i = i;
      lock.writeLock().unlock();
    }

    public boolean getB() {
      lock.readLock().lock();
      final boolean tmp = b;
      lock.readLock().unlock(),
      return tmp;
    }

    public void setB( final boolean b ) {
      lock.writeLock().lock();
      this.b = b;
      lock.writeLock().unlock();
    }
}

为了简单起见,我省略了 try...finally 在此示例中,锁周围的块。

我想知道是否有必要(或者说推荐)锁定/同步原始类型的 getter 和 setter?我知道Java中的赋值和返回操作是原子的。然而,通过使用这些锁,我不能确保每个访问器都获得最新值(等于使用 volatile)?

如果原语是怎么办 double 或者 long?

有帮助吗?

解决方案

这取决于。

但请注意,通常您需要在更粗粒度的级别上同步操作,例如:

Example e = ...;

synchronized (e) {
    e.setI(e.getI() + 10);
}

对于这种情况,您的内部锁是多余的。因此,也许在使用这些对象时应用外部同步比内部同步更好。

其他提示

java 中有类似 AtomicInteger 的东西,它可以很好地与多线程应用程序配合使用。

问问自己这个类是否可以实现为不可变类。它将更容易使用并且本质上是线程安全的。您不必担心并发、锁、同步等问题。

不可变类的示例:

final class Example {
    private final int i;
    private final boolean b;

    public Example(int i, boolean b){
        this.i = i ;
        this.b = b;
    }

    public int getI() {
        return i;
    }

    public boolean getB() {
        return b;
    }
}

我会设计您的应用程序,以便您不会同时访问这样的原始数据类型。添加如此低级别的锁定可能会大大降低应用程序的速度,因此不值得对应用程序进行多线程处理。

例如假设您有一个 32 核系统,它可以完美扩展并且运行速度比 1 核快 32 倍。然而,不带锁定的字段访问需要 1 ns,带锁定的字段访问需要 1 us (1000 ns),因此最终您的应用程序可能会慢约 30 倍。(慢 1000 / 快 32)如果只有 4 个核心,速度可能会慢数百倍,这从一开始就违背了多线程的目的。恕我直言。

没有必要锁定/同步原始类型的 getter 和 setter - 在大多数情况下将它们标记为 易失性就足够了(除了您提到的 double 和 long 之外)

正如之前的一篇文章提到的,您需要了解读取和更新序列,例如incrementI(int num),它可能会调用 getI() 和 setI() - 在这种情况下,您可以添加一个“同步的incrementI(int num)” num)' 方法到您的示例类。然后,锁定在更高级别完成,减少了对单独读取和写入锁定的需求,并且由于数据和行为保持在一起,因此是面向对象友好的。如果您同时读取/更新多个字段,则此技术更加有用。

不过,如果您只是一次读/写/更新一个字段,那么 AtomicXX 类更合适

您不应该对原始类型、String(它们是不可变的)和线程安全类型(例如“concurrent”包中的集合)使用锁。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top