3

获得对字段的访问权限的常用方法是同步 getter 和 setter。一个带有 int 的简单示例如下所示:

private int foo = 0;
public synchronized int get(){return this.foo;}
public synchronized void set(int bar){ this.foo = bar;}

现在,虽然这是使访问线程安全的一种安全方式,但它也表明一次只能读取一个线程foo

如果很多线程foo非常频繁地读取,并且只偶尔更新这个变量,那将是一个很大的浪费。相反,getter 可以被多个线程同时调用而没有任何问题。

有没有关于如何处理这个问题的既定模式?或者你将如何以最优雅的方式解决这个问题?

4

3 回答 3

5

看看ReadWriteLock。这个界面就是你要找的,它允许多个阅读器,但只有一个作者。

一个例子:

private int foo = 0;

private ReadWriteLock rwLock = /* use some implementation of ReadWriteLock here */;

public int get() {
    Lock l = rwLock.readLock();
    int result = 0;
    l.lock();
    try {
        result = this.foo;
    }
    catch(Exception ex) {
        // may throw the Exception here
    }
    finally {
        l.unlock();
    }
    return result;
}

public void set(int bar){ 
    Lock l = rwLock.writeLock();
    l.lock();
    try {
        this.foo = bar;
    }
    catch(Exception ex) {
        // may throw the Exception here
    }
    finally {
        l.unlock();
    }
}
于 2013-07-18T14:05:14.987 回答
3

如果您只是设置和获取变量:那么您可以使用volatile和删除synchronized方法。

如果您正在对整数进行任何操作,例如加法,您应该使用AtomicInteger.

编辑:

如果存在多次读取该字段并更新几次的情况,则有一种称为IMMUTABLE的模式。这是实现线程安全的方法之一。

class ImmutableClass{
        private final int a;

        public ImmutableClass(int a) {
            this.a  = a;
        }

        public int getA(){
            return a;
        }

        /* 
         * No setter methods making it immutable and Thread safe
         */
    }

有关不变性的更详细知识,Java Concurrency In practice是我建议您阅读的最佳资源。

更高级的方法:有一个读/写锁

于 2013-07-18T13:43:32.677 回答
0

对于像你这样简单的例子,在setter中只有一个字段并且没有复杂的逻辑来真正要求互斥,你可以只声明该字段volatile并删除synchronized关键字。

对于更复杂的东西,你可以使用便宜的读写锁模式:

public class CheapReadWriteLockPattern {

  // SINGLE-FIELD:
  private volatile Object obj;

  public Object read() {
    return obj;
  }

  public synchronized void write(Object obj) {
    this.obj = obj;
  }

  // MULTI-FIELD:
  private static class Ref {
    final Object x;
    final Object y;
    final Object z;

    public Ref(Object x, Object y, Object z) {
      this.x = x;
      this.y = y;
      this.z = z;
    }
  }

  private volatile Ref ref = new Ref(null, null, null);

  public Object readX() { return ref.x; }
  public Object readY() { return ref.y; }
  public Object readZ() { return ref.z; }

  public synchronized void writeX(Object x) {
    ref = new Ref(x, ref.y, ref.z);
  }
  public synchronized void writeY(Object y) {
    ref = new Ref(ref.x, y, ref.z);
  }
  public synchronized void writeZ(Object z) {
    ref = new Ref(ref.x, ref.y, z);
  }
}
于 2013-07-18T14:20:45.827 回答