2012-05-19 112 views
4

我跑以下代码:同步方法,而使用的等待()

class Counter extends Thread { 

static int i=0; 
//method where the thread execution will start 
public void run(){ 
    //logic to execute in a thread 

    while (true) { 
     increment(); 
    } 
} 

public synchronized void increment() { 
    try { 
     System.out.println(this.getName() + " " + i++); 
     wait(1000); 
     notify(); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

} 
//let’s see how to start the threads 
public static void main(String[] args){ 
    Counter c1 = new Counter(); 
    Counter c2 = new Counter(); 
    c1.setName("Thread1"); 
    c2.setName("Thread2"); 
    c1.start(); 
    c2.start(); 
} 
} 

是此代码的结果(添加的行编号):

1: Thread1 0 
2: Thread2 1 
3: Thread2 2 
4: Thread1 3 
5: Thread2 4 
6: Thread1 4 
7: Thread1 5 
8: Thread2 6 
stopping... 

由于增量方法是同步的并且由于其包含等待(1000)我没有预料到: 1.线程2打印2个连续打印:行2,3 我预计线程交错他们的打印 2.在第5,6行我仍然是4.

任何人都可以给我一个解释吗?

回答

1

您只在实例级同步。要同步所有Counter实例,您需要的increment方法为static以及​​。

由于它表示所有线程都可以自由运行,并发运行,因为它们不共享同步机制。

+2

代码或者你需要是常见的两种'Thread'情况下,在同一对象上同步。为此静态方法看起来像一个黑客。 – Gray

+0

@Gray - 是的,添加了更新 –

8

同步实例方法是这样的:

public synchronized void foo() { 
    ... 
} 

大致相当于:

public void foo() { 
    synchronized(this) { 
     ... 
    } 
} 

你看到这里的问题?同步在当前实例上完成。

由于您正在创建两个单独的Thread对象,因此每个increment方法将同步到一个不同的对象上,从而导致锁无效。

您应该让您的增量方法静态的(因此锁定类本身完成的),或者使用一个静态锁定对象:

private static final Object locker = new Object(); 

public void foo() { 
    synchronized(locker) { 
     ... 
    } 
} 

而且最后一个建议:在创建线程的首选方式java是通过执行Runnable,而不是扩展Thread

+0

并且更好地使用java.util.concurrent.locks.Lock API,并且您可能想要使用条件('lock.newCondition()')在线程之间进行通信。 –

+0

如果我通过实现Runnable来重写这个,我怎么能在打印时访问线程的名字? – Elad

+0

@Elad:和以前一样。只有'Counter c1 = new Counter();'变为'Thread t1 = new Thread(new Counter());''Counter'现在只是实现'Runnable'。那么你可以像't1.setName(“Thread1”);''一样。 – Tudor

0

这可能是你正在寻找

class Counter implements Runnable { 

    static int i = 0; 
    private Lock lock; 
    private Condition condition; 

    public Counter(Lock lock, Condition condition) { 

     this.lock = lock; 
     this.condition = condition; 
    } 


    public void run() { 
     while (true) { 
      lock.lock(); 
      try { 
       condition.await(1, TimeUnit.SECONDS); 
       System.out.append(Thread.currentThread().getName()).append(" ").println(i++); 
       condition.signalAll(); 
      } catch (InterruptedException e) { 
       throw new RuntimeException(e); 
      } 
     } 
    } 

    public static void main(String[] args) { 
     Lock lock = new ReentrantLock(true); 
     Condition condition = lock.newCondition(); 
     Executor e = Executors.newFixedThreadPool(2); 
     e.execute(new Counter(lock, condition)); 
     e.execute(new Counter(lock, condition)); 

    } 
} 
+0

谢谢!解决了在静态方法中调用wait()的问题! – Elad