假设我有两个哈希映射hashMap1和hashMap2,以及一个多线程并发Java程序。如果我放置一个同步块
synchronized(hashMap1) {
hashMap1.put(5, "Hello");
hashMap2.put(10, "Hi");
}
由于只有一个线程可以访问hashMap1,只有一个线程能够访问hashMap2吗?我本质上是在询问hashMap2是否会受到多个线程的保护,一次访问它就像hashMap1一样。
谢谢!
答案 0 :(得分:4)
不,synchronized
没有“锁定对象”。你的代码块所做的是需要一个线程在hashMap1进入块之前对其进行锁定。除了正在获取其监视器之外,hashMap1本身不会以任何方式“锁定”。 (也许将它称为监视器而不是锁定更清楚。)监视器是所有对象都具有的东西,它本身不会控制对它所属对象的访问。如果在其他地方访问hashMap2,则此同步块不会做任何事情来阻止它。
synchronized块的目的是要求线程获取监视器。您希望保护该资源免受并发访问的所有位置需要采用相同的锁。这是用synchronized
保护的代码块,告诉何时需要使用锁对象来控制访问。
监视器的选择可以与受保护的实际对象分开,以防止并发访问。您可以拥有一个专用的锁定对象并使用它,并不要求您必须对要保护的事物使用锁定。 (唯一的好处是它可能有助于组织,如果只有一件事你正在访问它可能会方便使用该东西的监视器。)使用专用锁可能更清楚:
public class Foo {
private final Object LOCK = new Object();
private Map hashMap1 = new HashMap();
private Map hashMap2 = new HashMap();
public void doStuff() {
synchronized(LOCK) {
... // do stuff with hashMap1 and hashMap2
}
}
}
保持对对象的私有访问权限意味着对象可以限制谁可以获取锁定(与synchronized(this)
不同)。也不要使用可以从程序的其他部分实习,缓存或以其他方式访问的字符串或布尔值等内容。
答案 1 :(得分:0)
答案取决于您的应用程序设计。毕竟,同步是一个选择加入的概念 - 任何线程都可以选择忽略锁定,无论如何都只是访问共享对象。
与您的示例类似,如果您确定hashMap2
的唯一访问权限位于示例中显示的synchronized块中,那么您实际上是通过锁定来保护它,尽管锁定了另一个对象。
对于未来的维护者来说,在对它们进行操作之前对两个对象进行锁定可能会更清楚。
答案 2 :(得分:0)
synchronized
关键字导致线程在进入方法时获得锁定,只有一个线程可以同时执行该方法(对于给定的对象实例,除非它是静态方法)。 / p>
在您的情况下,只要在synchronized
方法内部是唯一修改了hashmap2的地方,那么就可以保护它免受多个线程一次访问的影响。但是,如果除了synchronized
方法内部之外的其他地方正在修改hashmap2,则无法保证hashmap2将受到保护。