2

我遇到了 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();

    }
}

偶尔我会得到“在利比亚线程刚果很酷”,这不应该发生。我只期待:“在利比亚线程 libya awesome”“在刚果线程 congo cool”

我不希望它们混合在一起。

4

4 回答 4

5

The calls can interleave like the following:

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
于 2009-07-16T05:47:30.947 回答
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() );
            }
        }
    }
}
于 2009-07-16T05:57:19.303 回答
3

它可能是这个顺序,所以它是正确的:

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

因此,您确实有某种意义上的竞争条件。每当您尝试调用同步方法时,同步都会获取锁,因此您需要另一种方式来暗示对变量的同步访问。例如,您可以从方法中删除同步并执行以下操作:

public void run() 
{
  for (int i = 0; i  10; i++) 
  {
   synchronized(v)
   {
      v.setValue( "caller", "value" );
      v.getValue();
   }
  }
}
于 2009-07-16T05:50:14.090 回答
3

对 getValue() 和 setValue() 的调用可能是交错的。

也就是说,没有线程会在 getValue() 中同时另一个线程在 getValue() 或 setValue() 中,同样没有线程将在 setValue() 中,而另一个线程在 getValue() 或 setValue() 中。

但是,不能保证单个线程会连续调用 setValue() getValue() 而不会被另一个线程抢占。

基本上,这是完全合法且可能的:

线程 1:v.setValue()
其他线程:任意数量的 v.getValue()'s/v.setValue()'s
线程 1:v.getValue()

于 2009-07-16T05:50:54.277 回答