2009-07-16 94 views
2

我在与同步行为不我所期望的方式问题,我使用volatile关键字尝试也:的Java同步问题

共享对象


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

    } 
} 

偶尔我得到“在利比亚主题刚果酷” 这绝不应该发生。我只希望: “在利比亚线程利比亚真棒” “在刚果线程刚果酷”

我不指望他们混合。

回答

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

到的getValue()和setValue方法(的呼声)可交错。

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

但是,不能保证单个线程将顺序调用setValue()getValue()而不被其他线程抢占。

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

线程1:v.setValue()
其他线程(S):任何数量的v.getValue()的/ v.setValue ()的
主题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 2009-07-16 19:00:05