2010-08-16 4 views
17

У меня есть два потока. Один вызывает метод обновления класса, который изменяет переменную. Другой вызывает метод обновления класса, который читает переменную. Только один поток пишет и один (или более) поток читает эту переменную. Что мне нужно делать с точки зрения параллелизма, поскольку я новичок в многопоточности?Java разделяет переменную между двумя потоками

public class A 
{ 
    public int variable; // Does this need to be volatile? 
     // Not only int, could also be boolean or float. 
    public void update() 
    { 
     // Called by one thread constantly 
     ++variable; 
     // Or some other algorithm 
     variable = complexAlgorithm(); 
    } 
} 

public class B 
{ 
    public A a; 
    public void update() 
    { 
     // Called by another thread constantly 
     // I don't care about missing an update 
     int v = a.variable; 
     // Do algorithm with v... 
    } 
} 

Спасибо,

+2

Многие из нижеприведенных ответов предполагают, что вы выполняете целые манипуляции, которые могут обрабатываться классом AtomicInteger. Для чего-то более сложного, посмотрите на «синхронизированный» блок или 'java.util.conccurent.locks.Lock' – justkt

ответ

17

Если есть одна и только одна нить, которая записывается в variable, вы можете сойти с рук volatile. В противном случае см. Ответ с AtomicInteger.

Только volatile будет работать только в одном потоке записи, потому что есть только одна нитка для записи, поэтому она всегда имеет правильное значение variable.

+0

Это была моя точка. Я знаю, что только один поток изменяет его, но может быть много потоков, читающих его. – Dave

+0

@Dave - ну, вот почему я отправил этот ответ. Если ваша многопоточность проста, записывается только один поток, и у вас есть только одна переменная, которую она записывает для чтения других потоков, вам не нужно сложное решение, волатильная переменная int. В общем случае вы, вероятно, захотите Locks, synchonized или AtomicInteger. Но ваш вопрос был довольно конкретным в отношении количества потоков писателей и количества задействованных переменных. Не пугайтесь голосов по другим ответам. Если мое решение удовлетворит ваши потребности, примите его. – hidralisk

+0

Большое спасибо, мне просто нужно второе мнение. Я также никогда не знал об атомных переменных и других позитивах в пакете параллелизма, которые я счастлив, люди здесь были достаточно любезны, чтобы объяснить. Это может оказаться ценным для меня в будущем. – Dave

8

не только должны быть variablevolatile, но вы также хотите, чтобы защитить вашу update функцию с some sort of synchronization так ++variable не атомный вызов. Это, в конце концов, просто синтаксический сахар для

variable = variable + 1; 

, который не является атомарным.

Вы также должны обернуть любые вызовы, которые читают переменную в некотором виде lock.

В качестве альтернативы используйте AtomicInteger. Это было сделано для такого рода вещей (только для целочисленных операций).

public class A 
{ 
    // initially had said volatile wouldn't affect this variable because 
    // it is not a primitive, but see correction in comments 
    public final AtomicInteger variable; // see comments on this issue of why final 
    public void update() 
    { 
     // Called by one thread constantly 
     variable.getAndIncrement(); // atomically adds one 
    } 
    public int retrieveValue() 
    { 
     return variable.get(); // gets the current int value safely 
    } 
} 

public class B 
{ 
    public A a; 
    public void update() 
    { 
     // Called by another thread constantly 
     int v = a.retrieveValue(); 
     // Do algorithm with v... 
    } 
} 

Для более сложных алгоритмов, как предполагает ваше недавнее изменение, используйте синхронизацию или блокировки.

+0

Говоря« какой-то замок », вы имеете в виду« поместить его в синхронизированный блок или сделать синхронизированный метод «не так ли? Кроме того, +1 с AtomicInteger – Riduidel

+0

Или используйте 'java.util.concurrent.Lock' какой-то. Я предпочитаю, чтобы более «синхронизированный» для большей выразительности - мне особенно нравится «ReadWriteLock». – justkt

+2

Ваш комментарий: «volatile не повлияет на это, это не примитив» вводит в заблуждение. Это не имеет никакого отношения к тому, является ли поле примитивным, но все связано с тем, что 'variable' больше не переназначается. Здесь вам будет сообщено окончание 'variable'. –

9

В этом случае я бы использовал AtomicInteger, однако обобщенный ответ заключается в том, что доступ к переменной должен быть защищен синхронизированным блоком или с использованием другой части пакета java.util.concurrent.

Несколько примеров:

Использование синхронизации

public class A { 
    public final Object variable; 
    public void update() { 
     synchronized(variable) { 
      variable.complexAlgorithm(); 
     } 
    } 
} 

public class B { 
    public A a; 
    public void update() { 
     sychronized(a.variable) { 
      consume(a.variable); 
     } 
    } 
} 

Использование java.util.concurrent

public class A { 
    public final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); 
    public final Object variable; 
    public void update() { 
     lock.writeLock().lock(); 
     try { 
      variable.complexAlgorithm(); 
     } finally { 
      lock.writeLock().unlock(); 
     } 
    } 
} 

public class B { 
    public A a; 
    public void update() { 
     a.lock.readLock().lock(); 
     try { 
      consume(a.variable); 
     } finally { 
      a.lock.readLock().unlock(); 
     } 
    } 
} 
+0

Можете ли вы объяснить, почему не переменная.getWriteLock(). Lock() в классе A? – Radu

+0

Вы можете синхронизировать только объект, и этот объект должен быть окончательным. В этом примере синхронизация выполняется с помощью реализации ReadWriteLock (поэтому одновременное чтение нескольких потоков) - см. Http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock .html –

4

Использование AtomicInteger или synchronize доступ к безопасным.

+0

не могли бы вы объяснить, что вы подразумеваете под синхронизацией? Как там, куда он должен идти, его немного запутывает для меня. – Dave

+0

@Dave - http://download.oracle.com/javase/tutorial/essential/concurrency/sync.html должен помочь вам с базовой синхронизацией Java. – justkt

Смежные вопросы