Синхронизация Java с записями в статической карте - PullRequest
1 голос
/ 10 октября 2011

У меня есть статическая карта, к которой мне нужно синхронизировать доступ. Карта вводится с помощью идентификатора пользователя. Я хочу оптимизировать синхронизацию таким образом, чтобы не блокировать все потоки, где я мог бы блокировать только потоки, которые относятся к одному и тому же идентификатору пользователя.

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 является статической, записи являются фактически статическими, то есть я все еще держу глобальную блокировку ( т.е. синхронизация с объектом класса)?

Ответы [ 3 ]

1 голос
/ 10 октября 2011

Нет, у вас все хорошо: каждая запись на карте - это отдельный объект, поэтому синхронизация на записи на карте не будет синхронизироваться ни на карте, ни в классе, который владеет картой.

(Кстати, ваш метод #getMapEntry (...) фактически возвращает значение , а не запись . Запись карты содержит ссылки как на ключ, так и на значение.)

0 голосов
/ 10 октября 2011

Вы не синхронизируете объект класса, но я делаю то, что вы думаете:

  • Различные потоки получают доступ к Карте с использованием общего доступа s_lock. Но я думаю, что вы также можете сделать s_users final и synchronize на этом

  • Различные потоки, обращающиеся к одному и тому же объекту User, выполняют «трудоемкую операцию» "в последовательности.

Единственное предостережение, которое я вижу, это то, что Объект продолжает изменяться на карте для одного и того же User. Пока у вас есть только один User объект для одного userId, все в порядке.

Я сделал нечто подобное, но синхронизировался на userId.intern(). У него есть свои недостатки, но он хорошо работает для моего случая.

0 голосов
/ 10 октября 2011

Это должно работать; второй блок синхронизируется только для этого пользователя.

Небольшой тест:

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

Так что все хорошо.

...