Java-класс для одновременного чтения нескольких потоков или изменения одного - PullRequest
8 голосов
/ 22 ноября 2011

Допустим, у вас есть следующий класс:

class A {
    private Foo foo = new Foo();
    Foo getFoo() {
        return foo; //foo.clone()?
    }
    void modifyFoo() {
        //modify this.foo
        //...
    }
}

Я хочу разрешить:

  • либо несколько потоков для вызова getFoo()
  • или один поток для вызова modifyFoo(),
  • когда поток хочет изменить foo, другие новые вызовы getFoo(), поступающие после этого, не могут быть выполнены, пока не будет выполнено изменение.

Есть ли уже классы для этой проблемы в Java или я должен ее реализовать? Если мне нужно это реализовать, то как мне это реализовать, чтобы обеспечить безопасность потоков?

Ответы [ 4 ]

13 голосов
/ 22 ноября 2011

Звучит так, будто вы ищете блокировку чтения-записи, к счастью, java предоставляет ее, ReentrantReadWriteLock. Вы можете использовать его следующим образом:

class A {
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private Foo foo = new Foo();
    Foo getFoo() {
        lock.readLock().lock();
        try {
            Foo tmp = foo; //foo.clone()?
        } finally {
            lock.readLock().unlock();
        }
        return tmp;
    }
    void modifyFoo() {
        lock.writeLock().lock();
        try {
            //modify this.foo
            //...
        } finally {
            lock.writeLock().unlock();
        }
    }
}

Это позволит любому количеству потоков одновременно вызывать getFoo(), но только одному вызову modifyFoo(). Когда вызывается метод модификации foo, поток будет блокироваться до тех пор, пока не будут сняты все блокировки чтения, затем начнет выполняться и предотвратит получение любых новых блокировок чтения до тех пор, пока он не будет завершен. Есть еще проблемы параллелизма, так как возвращаемый Foo может быть изменен кодом, который вызывает getFoo, но это должно обеспечить базовый инструмент, который вам нужен.

4 голосов
/ 22 ноября 2011

Вы должны использовать ReentrantReadWriteLock . Несколько потоков могут читать, один поток может написать, который блокирует все чтения.

1 голос
/ 22 ноября 2011
class A {
    private volatile Foo foo = new Foo();
    Foo getFoo() {
        return foo; //foo.clone()?
    }
    void synchronized modifyFoo() {
        //modify this.foo
        //...
    }
}

Ключевое слово synchronized гарантирует, что modifyFoo() является атомарным, то есть не позволит нескольким потокам вызывать его одновременно. Ключевое слово volatile гарантирует, что чтение в foo не вернет кэшированную версию (которая могла бы устареть, если бы другой поток изменил ее), а вместо этого возвращает текущее правильное значение.

0 голосов
/ 22 ноября 2011

Вы должны быть в состоянии обойтись с синхронизированным блоком.

class A {
    private Foo foo = new Foo();

    Foo getFoo() {
        return foo;
    }

    void modifyFoo() {
        synchronized(foo){
            /* do your modify stuff */
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...