我运行了以下代码:
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.
有人可以给我一个解释吗?
答案 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));
}
}