在具有实例变量的块上使用synchronized

时间:2017-02-15 20:09:53

标签: java multithreading synchronization

当我通过实例变量同步一个块时,它的变量可以被其他线程访问(不编辑)?

示例:

如果线程调用setValue,则value会被锁定。 但如果另一个线程在锁定期间调用getValue,我也不知道此调用是否进入等待模式。

setValue(Integer newValue){
    synchronized (this.value){
        this.value = newValue;
    }
}

getValue(){
     return this.value;
}

4 个答案:

答案 0 :(得分:2)

当您在某个对象上进行同步时,并不意味着此对象已被锁定" - 这意味着你获得了所谓的"内在锁定"与对象关联(每个对象都有一个)。

当某些同步块被某个对象保护时,它基本上意味着您需要获取与该对象关联的内部锁以进入该块。当您离开同步阻止时 - 您也将释放锁定。

与同步方法类似 - 在这种情况下"这个"引用用于保护方法。

所以"价值"当一些线程在同步块内时,用于保护同步块的对象不会被锁定。

您可以通过以下方式轻松测试:

public class Test {

    Counter lockObject = new Counter();

    public static void main(String[] args) {
        new Test().go();
    }

    private void go() {
        new Thread(() -> {
            synchronized (lockObject) {
                while(true) {
                    System.out.println("Inside thread");
                }
            }
        }).start();

        while(true) {
            lockObject.inc();
            System.out.println(String.format("Accessing lock object: %d", lockObject.get()));
        }
    }
}

class Counter {
    int i = 0;
    public void inc() {
        i++;
    }
    public int get() {
        return i;
    }
}

这里的线程永远位于由" lockObject"保护的同步块内。但是stil主线程可以与它进行交互。

答案 1 :(得分:1)

  

我希望那么多线程访问我的地图但按键同步...   并且所有线程都通过密钥传递

来访问任何值

您可以使用ConcurrentHashMap

由于只对相关密钥执行锁定,因此读取操作很便宜而且不会阻塞。

1)如果您认为未更新的读数不是问题,那么当您从地图执行get()时,您不会被迫同步地图。
这似乎是你的用例。

2)如果在示例中与映射中的键关联的值必须反映精确值,则可以同步setValue()方法以确保在映射值中充分考虑并发调用。

请注意,setValue()方法只有在其中执行的代码根据当前地图状态修改地图时才应同步。
否则你不需要同步它。

例如:

public class ExampleClass{

  private Map<Character, Integer> map = new ConcurrentHashMap<>();

  void synchronized setValue(String key, Integer newValue){ 
        // some processings ...            
        this.map.put(key, newValue);       
  }

  Integer getValue(String key){
     return map.get(key);
  }
}

答案 2 :(得分:1)

  

当我通过实例变量同步块时......

您无法在变量上进行同步,您只能在对象上进行同步。您的代码执行此操作:

synchronized (lockObject) {
    ...
}

这不是在名为lockObject的变量上进行同步;您的代码正在new Counter()变量引用的lockObject实例上进行同步。

  

......它的变量可以被访问......?

synchronized块不会阻止其他线程修改lockObject变量,也不会阻止其他线程修改Counter实例。 synchronized块阻止的唯一事情是,它阻止其他线程同时在同一个对象上同步。

如果你想阻止两个线程同时使用Counter,那么你可以在你的代码使用它的每个地方包裹一个synchronized(lockObject)块。

答案 3 :(得分:1)

  

您可以使用ConcurrentHashMap。

我也很喜欢这个。

补充此链接,其中有一个很好的解释和其他类型的地图。

HashMap vs ConcurrentHashMap vs SynchronizedMap

干杯。