2009-07-16 5 views
2

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

Shared Object:


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; 
} 
} 

Тема 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(); 
    } 
    } 
} 

Резьба 2:


class LibyaThread implements Runnable { 
    private ThreadValue v; 
    public LibyaThread(ThreadValue v) { 
    this.v = v; 

    } 
    public void run() { 
    for (int i = 0; i 10; i++) { 
     v.setValue("libya", "awesome"); 
     System.out.println("In Libya Thread " + v.getValue()); 

    } 
    } 
} 

Вызов Класс:


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(); 

    } 
} 

Иногда я получаю «В Ливии конго темы прохладно» , который никогда не должно произойти. Я ожидаю только: «В Ливии Тема Libya awesome» «В Конго Нить конго прохладно»

Я не ожидаю, что они будут смешанными.

ответ

5

Вызовы можно чередовать как следующее:

Thread 1 : v.setValue() 
Thread 2 : v.setValue() 
Thread 1 : v.getValue() // thread 1 sees thread 2's value 
Thread 2 : v.getValue() // thread 2 sees thread 2's value 
3

Это может быть в таком порядке, так что это правильно:

v.setValue("libya", "awesome"); 
//context switch 
v.setValue("congo", "cool"); 
//context switch 
System.out.println("In Libya Thread " + v.getValue()); 

Поэтому у вас есть гонки условия в некотором смысле. Synchronized получает блокировку всякий раз, когда вы пытаетесь вызвать синхронизированный метод, поэтому вам нужен другой способ подразумевать синхронизированный доступ к переменной. Например, вы можете удалить синхронизированные из методов и сделать следующее:

public void run() 
{ 
    for (int i = 0; i 10; i++) 
    { 
    synchronized(v) 
    { 
     v.setValue("caller", "value"); 
     v.getValue(); 
    } 
    } 
} 
3

Призывы ПолучитьЗначение() и SetValue() могут чередоваться.

То есть ни один поток не будет в getValue(), в то время как другой поток находится в getValue() или setValue(), и ни один поток не будет в setValue(), а другой поток находится в getValue() или setValue().

Однако нет никакой гарантии, что один поток будет выполнять последовательные вызовы setValue() getValue(), не будучи вытесненными другим потоком.

В принципе, это совершенно законно и возможно:

Тема 1: v.setValue()
Некоторые Другие темы (ы): Любое количество v.getValue() 's/v.setValue() 's
тема 1: v.getValue()

4

Это должно вам поведение, которое вы ищете.

Тема 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++) { 
      synchronized(v) { 
       v.setValue("congo", "cool"); 
       System.out.println("In Congo Thread " + v.getValue()); 
      } 
     } 
    } 
} 

Тема 2:

class LibyaThread implements Runnable { 
    private ThreadValue v; 

    public LibyaThread(ThreadValue v) { 
     this.v = v; 
    } 

    public void run() { 
     for (int i = 0; i < 10; i++) { 
      synchronized(v) { 
       v.setValue("libya", "awesome"); 
       System.out.println("In Libya Thread " + v.getValue()); 
      } 
     } 
    } 
} 
+1

В нетривиальной программы, вы, вероятно, хотите, чтобы скрыть даже этот уровень синхронизации. Имея такой метод, как setValueAndReturnString(), он сам синхронизируется.Вы не хотите полагаться на звонящих, обрабатывающих многопоточность правильно. – AngerClown

+0

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