Java Synchronized e Threads
-
16-09-2019 - |
Pergunta
Estou tendo problemas com Synchronized não se comportar da maneira que eu esperar, eu tentei usar palavra-chave volátil também:
objeto compartilhado:
public class ThreadValue {
private String caller;
private String value;
public ThreadValue( String caller, String value ) {
this.value = value;
this.caller = caller;
}
public synchronized String getValue() {
return this.caller + " " + this.value;
}
public synchronized void setValue( String caller, String value ) {
this.caller = caller;
this.value = value;
}
}
Thread 1:
class CongoThread implements Runnable {
private ThreadValue v;
public CongoThread(ThreadValue v) {
this.v = v;
}
public void run() {
for (int i = 0; i < 10; i++) {
v.setValue( "congo", "cool" );
v.getValue();
}
}
}
Thread 2:
class CongoThread implements Runnable {
private ThreadValue v;
public CongoThread(ThreadValue v) {
this.v = v;
}
public void run() {
for (int i = 0; i < 10; i++) {
v.setValue( "congo", "lame" );
v.getValue();
}
}
}
Chamar Classe:
class TwoThreadsTest {
public static void main (String args[]) {
ThreadValue v = new ThreadValue("", "");
Thread congo = new Thread( new CongoThread( v ) );
Thread libya = new Thread( new LibyaThread( v ) );
libya.start();
congo.start();
}
}
Ocasionalmente eu recebo "In Libya Thread congo cool"
que nunca deveria acontecer. Espero apenas:
"In Libya Thread libya awesome"
"In Congo Thread congo cool"
Eu não esperar que eles sejam misturados.
Solução
O que acontece é o follwing:
- Tópico 1 define o valor
- Tópico 2 conjuntos o valor
- Passe 1 lê o valor definido pela linha 2.
Para corrigir isso, você precisa ter um bloqueio objeto que guarda a / funções definidas get chamar para ambos os tópicos. A melhor maneira de fazer isso, é fazer com que um método sincronizado extra que faz tanto o set e get. No entanto, por vezes, que não é desejável. Nesse caso, dar a ambos os tópicos um objeto de bloqueio. Que é apenas um objeto simples. Que, em seguida, usar em um bloco sincronizado.
Implementação de cada thread gostaria como o seguinte, nota que eles precisam ter exatamente o mesmo objeto!
Object lockObject = new Object();
Thread t1 = new CongroThread(v, lockObject);
Thread t2 = new LibyaThread(v, lockObject);
...
class CongoThread implements Runnable {
private ThreadValue v;
private Object lockObject;
public CongoThread(ThreadValue v, Object lockObject) {
this.v = v;
this.lockObject = lockObject,
}
public void run() {
for (int i = 0; i < 10; i++) {
synchronized(lockObject)
{
v.setValue( "congo", "lame" );
v.getValue();
}
}
}
}
Outras dicas
Você só está sincronizar o acesso a getValue
e setValue
separadamente e não o de dois forro
v.setValue( "congo", ..);
v.getValue();
Então, naturalmente, os dois segmentos podem entrelaçar entre um de setValue
e getValue
Você synchronze as chamadas System.out.print? Sem sincronização, eles são thread-safe, mas pode não emitem na ordem correta.
synchronzied(System.out) {
System.out.print(....);
System.out.flush();
}