当我通过实例变量同步一个块时,它的变量可以被其他线程访问(不编辑)?
示例:
如果线程调用setValue
,则value
会被锁定。
但如果另一个线程在锁定期间调用getValue
,我也不知道此调用是否进入等待模式。
setValue(Integer newValue){
synchronized (this.value){
this.value = newValue;
}
}
getValue(){
return this.value;
}
答案 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
干杯。