Java синхронизированная проблема - PullRequest
2 голосов
/ 16 июля 2009

У меня проблемы с тем, что Synchronized ведет себя не так, как я ожидал, я пытался использовать ключевое слово volatile:

Общий объект:


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

    }
}

Иногда я получаю "В Ливии Нить круто, Конго" что никогда не должно случиться. Я ожидаю только: "В Ливии Нить Ливия потрясающая" "In Congo Thread congo cool"

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

Ответы [ 4 ]

5 голосов
/ 16 июля 2009

Вызовы могут чередоваться следующим образом:

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
4 голосов
/ 16 июля 2009

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

Тема 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() );
            }
        }
    }
}
3 голосов
/ 16 июля 2009

Вызовы getValue () и setValue () могут чередоваться.

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

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

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

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

3 голосов
/ 16 июля 2009

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

 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();
   }
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...