假设我有以下代码:
private ConcurrentHashMap<Integer, Book> shelf;
public Library(ConcurrentHashMap<Integer, Book> shelf){
this.shelf = new ConcurrentHashMap<Integer, Book>(shelf);
}
鉴于我使用的是线程安全集合,可以使用以下方法还是需要担心线程安全?
public void addBook(int index, Book add){
shelf.put(index, add);
}
如果上述方法使用不安全,添加同步是否是正确的方法?这样
public synchronized void addBook(int index, Book add){
shelf.put(index, add);
}
如果您只调用shelf.put
,则无需担心。由于put
已经是线程安全的,因此您可以。
当您执行多个需要原子操作时,您需要担心同步。例如,也许您有一个名为 updateBook
的方法,如下所示
public void updateBook(int index, String newTitle){
Book book = shelf.get(index);
// do something with book or maybe update book.setTitle(newTitle);
shelf.put(index, book);
}
必须synchronized
此方法,因为否则其他线程可能会获得尚未更新的书籍。
synchronized
关键字实质上是在整个addBook
方法周围放置了一个互斥锁。
ConcurrentHashMap
可确保所有操作(例如 put)都是线程安全的,但结合使用检索操作(例如 get)可能会导致您遇到以下情况:您在放置的同时从 Hashmap 中检索内容,并获得意外结果。
单独地,ConcurrentHashMap
中的所有方法都是线程安全的,但在单独的线程中结合使用时,您不一定确定它们的执行顺序。(感谢@jtahlborn的澄清)。
因此,在您的特定情况下,将 synchronized
关键字添加到 addBook
方法是多余的。
如果您正在执行涉及多个检索和放置的更复杂的操作,则可能需要考虑一些无关的锁定(您自己的互斥锁)。
请参阅:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html