我有一个静态Map,我需要同步访问。地图由用户ID键控。我想优化同步,以便我不会阻止所有线程,我只能阻止与相同用户ID相关的线程。
private static Object s_lock = new Object();
private static Map<String,User> s_users = new HashMap();
...
private someMethod() {
synchronized(s_lock)
{
// keeping the global lock for as little as possible
user=getMapEntry();
}
synchronized(user) <-------- (1)
{
// time consuming operation
// hopefully only blocking threads that relate to same user id.
}
}
...
private User getMapEntry(String userId)
{
if (s_users.containsKey(userId)) {
user = s_users.get(userId);
}
else {
user = new User();
user.id = userId;
s_users.put(userId, user);
}
return user;
}
我的问题是 - 在(1)我假设我没有持有'全局'同步锁,但由于s_users地图是静态的,这些条目是否有效静态,这意味着我仍然持有全局锁(即在类对象上同步?)
答案 0 :(得分:1)
不,你很好:每个地图条目都是一个单独的对象,因此在地图条目上的同步不会在地图上同步,也不会在拥有地图的类上同步。
(顺便说一下,你的#getMapEntry(...)方法实际上返回一个值,而不是一个条目。一个map条目包含对一个键的引用和一个值。)
答案 1 :(得分:0)
这应该有用;第二个块仅在此用户上同步。
小测试:
public class Test {
protected class User {
String id;
}
private static Object s_lock = new Object();
private static Map<String,User> s_users = new HashMap<String, User>();
public void someMethod(String id) throws InterruptedException {
User user;
synchronized(s_lock)
{
// keeping the global lock for as little as possible
user = getMapEntry(id);
}
synchronized(user)
{
System.out.println("Waiting for user: "+user.id);
Thread.sleep(10000);
System.out.println("Finished waiting for user: "+user.id);
}
}
private User getMapEntry(String userId)
{
User user;
if (s_users.containsKey(userId)) {
user = s_users.get(userId);
}
else {
user = new User();
user.id = userId;
s_users.put(userId, user);
}
return user;
}
public static void main(String[] args) throws InterruptedException {
final Test test = new Test();
for(int i = 0; i < 10; i++) {
final int j = i;
new Thread() {
public void run() {
try {
test.someMethod(String.valueOf(j % 5));
} catch (InterruptedException e) {}
}
}.start();
}
}
}
输出:
Waiting for user: 0
Waiting for user: 1
Waiting for user: 3
Waiting for user: 2
Waiting for user: 4
Finished waiting for user: 0
Finished waiting for user: 1
Waiting for user: 1
Waiting for user: 0
Finished waiting for user: 3
Finished waiting for user: 2
Waiting for user: 3
Waiting for user: 2
Finished waiting for user: 4
Waiting for user: 4
Finished waiting for user: 0
Finished waiting for user: 1
Finished waiting for user: 3
Finished waiting for user: 2
Finished waiting for user: 4
所以没关系。
答案 2 :(得分:0)
你没有在类对象上同步,但我正在做你认为它正在做的事情:
不同的主题使用共享的s_lock
访问地图。但我认为您也可以{/ 1}} s_users
和final
访问相同synchronize
对象的不同线程执行“耗时的操作”
“按顺序。
我看到的唯一注意事项是对象是否在地图中保持同一User
的变化。只要一个User
只有一个User
对象,你就可以了。
我做了类似的事情但在userId
上同步了。它有它的缺点,但对我的情况很好。