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.

Foi útil?

Solução

O que acontece é o follwing:

  1. Tópico 1 define o valor
  2. Tópico 2 conjuntos o valor
  3. 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();
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top