2009-07-16 3 views
3

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

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

    } 
    } 
} 

Calling Класс:


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» «В Конго Тема конго прохладно»

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

+0

Дубликат http://stackoverflow.com/questions/1135502/java-synchronized-and-threads и http://stackoverflow.com/questions/1137475/java-thread-shared-object-synchronization- проблема - уже много раз ответили. – Bombe

+0

@Bombe второй «дубликат» - вот этот вопрос –

ответ

0

Проблема заключается в том, что v.getValue() для потока Ливии вызывается сразу после того, как поток Конго вызвал v.setValue(), что привело к вашему перемешиванию.

Решение состоит в том, чтобы иметь поток блока BOTH значения get и set, иначе вы продолжите эту проблему. Вам нужно будет вызвать получателя внутри установщика или использовать wait/notify, чтобы другой поток ожидал, пока один поток не установит и не получит значение.

4

Почему они не смешиваются? Хотя каждый индивидуальный вызов синхронизирован, нет ничего, чтобы остановить один поток от вызова v.setValue, а затем поток, вызывающий setValue, затем первый поток, вызывающий getValue(). Я считаю, что это то, что происходит. Вы можете избежать этого с помощью:

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

Таким образом, на каждой итерации убеждается, что он называет setValueиgetValue без другого потока вызывающего setValue в то же время.

Это не идеальный дизайн, правда, - но я предполагаю, что это демонстрация более понять синхронизации, чем все остальное :)

+1

В целом, это плохая практика блокировки «реальных» объектов. используйте отдельный объект для блокировки, этот объект должен использоваться только для блокировки одной частичной функции. – Thirler

+0

Да, я согласен ... Я надеюсь, что это всего лишь педагогический пример. –

2

Что то происходило follwing:

  1. резьбы 1 устанавливает значение
  2. резьба 2 устанавливает значение
  3. резьба 1 считывает значение, установленное с помощью нити 2.

Чтобы исправить это, вам нужно иметь 1 объект блокировки, который защищает вызовы get/set для обоих потоков. Лучший способ сделать это - сделать дополнительный синхронизированный метод, который выполняет как набор, так и get. Однако иногда это нежелательно. В этом случае оба потока создайте объект блокировки. Это просто простой объект. Затем они используются в синхронизированном блоке.

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

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("libya", "awesome"); 
       System.out.println("In Libya Thread " + v.getValue()); 
      } 
     } 
    } 
}