使用wait()时的同步方法

时间:2012-05-19 12:19:52

标签: java multithreading wait synchronized

我运行了以下代码:

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...

由于increment方法是同步的,因为它包含wait(1000)我没想到: 1. Thread2打印2个连续打印:2,3行 我期望线程交错他们的印刷品 2.在第5,6行,我仍然是4.

有人可以给我一个解释吗?

3 个答案:

答案 0 :(得分:9)

这样的同步实例方法:

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

答案 1 :(得分:1)

您只是在实例级别进行同步。要在所有Counter个实例之间进行同步,您需要increment方法static以及synchronized

因为它所有的线程都是自由运行的,彼此并发运行,因为它们没有共享同步机制。

答案 2 :(得分: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));

    }
}