平时用Condition 少,最近来学一下,利用Condition 交替打印 数字和字母 1a2b3c, 一直有问题,找了资料看,也没搞明白自己的问题,去问答里面问人,也没人鸟。今晚捣鼓出来了,写一下遇到的问题和解决。以下代码是 遇到锁,唤醒不了,一直等待。 叫版A吧
public class LockAndCondition {
@Test
public void t1() throws InterruptedException {
Lock lock = new ReentrantLock();
Masthead m1 = new Masthead(new Object[]{1, 2, 3}, lock, "T1");
Masthead m2 = new Masthead(new Object[]{"A", "B", "C"}, lock, "T2");
m1.start();
Thread.sleep(1000);
m2.start();
m1.join();
m2.join();
}
}
class Masthead extends Thread {
Object[] data;
Lock lock;
Condition condition;
String name;
public Masthead(Object[] data, Lock lock, String name) {
this.data = data;
this.lock = lock;
this.condition = lock.newCondition();
this.name = name;
setName(name);
}
@Override
public void run() {
try {
lock.lock();
for (Object d : data) {
System.out.println(d);
condition.signalAll();
condition.await();
}
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
只会打印出 1A,就一直无限等待了,按我的理解,应该是在等待之前再唤醒另一个线程工作,怎么都在等待。 看了快照 说 java.lang.Thread.State: WAITING (on object monitor),就是等待被唤醒,那奇怪了,condition.signalAll(); 没起效吗? 找了挺多资料看,也没搞懂。后面发现,lock是同一把锁了,但是 条件condition 不是, 线程里的都是 new出来的,
this.condition = lock.newCondition();
所以,同一把锁,不同条件condition, 唤醒不了不同的 condition 等待对象,哎 到这里 终于也好了
修改好,版B
public class LockAndCondition {
@Test
public void t1() throws InterruptedException {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
Masthead m1 = new Masthead(new Object[]{1, 2, 3}, lock, condition, "T1");
Masthead m2 = new Masthead(new Object[]{"A", "B", "C"}, lock, condition, "T2");
m1.start();
Thread.sleep(1000);
m2.start();
m1.join();
m2.join();
}
}
class Masthead extends Thread {
Object[] data;
Condition condition;
String name;
Lock lock;
public Masthead(Object[] data, Lock lock, Condition condition, String name) {
this.data = data;
this.condition = condition;
this.name = name;
this.lock = lock;
setName(name);
}
@Override
public void run() {
for (Object d : data) {
lock.lock();
System.out.println(d);
condition.signalAll();
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
这时,可以打印出 1A2B3C ,但是 又发现新的问题,按理说,我线程内容都执行完了,为什么,主线程没继续往下走,卡着了? jstack 一下, 又是 java.lang.Thread.State: WAITING (on object monitor), 又在等待唤醒? 主线程还要唤醒? 不是join的吗? 子线程完了 主线程就可以继续走了的
看了几遍,难不成, await() 有问题? 还是说没解锁?
猜想验证
public class LockAndCondition {
@Test
public void t1() throws InterruptedException {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
Masthead m1 = new Masthead(new Object[]{1, 2, 3}, lock, condition, "T1");
Masthead m2 = new Masthead(new Object[]{"A", "B", "C"}, lock, condition, "T2");
m1.start();
Thread.sleep(1000);
m2.start();
m1.join();
m2.join();
}
}
class Masthead extends Thread {
Object[] data;
Condition condition;
String name;
Lock lock;
public Masthead(Object[] data, Lock lock, Condition condition, String name) {
this.data = data;
this.condition = condition;
this.name = name;
this.lock = lock;
setName(name);
}
@Override
public void run() {
for (Object d : data) {
lock.lock();
System.out.println(d);
condition.signalAll();
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println("解锁"+d);
}
}
}
}
1
A
解锁1
2
解锁A
B
解锁2
3
解锁B
C
解锁3
到了,C这里, 没解锁。也就是 打印了c之后, await(),没有被唤醒,无限等待了。另一个线程早就执行完退出了,不可能再来唤醒,对题目来说也不对。那么 按照打破锁的 军规,就当前情况就该有个超时解锁,那么 await(时间)
public class LockAndCondition {
@Test
public void t1() throws InterruptedException {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
Masthead m1 = new Masthead(new Object[]{1, 2, 3}, lock, condition, "T1");
Masthead m2 = new Masthead(new Object[]{"A", "B", "C"}, lock, condition, "T2");
m1.start();
Thread.sleep(1000);
m2.start();
m1.join();
m2.join();
}
}
class Masthead extends Thread {
Object[] data;
Condition condition;
String name;
Lock lock;
public Masthead(Object[] data, Lock lock, Condition condition, String name) {
this.data = data;
this.condition = condition;
this.name = name;
this.lock = lock;
setName(name);
}
@Override
public void run() {
for (Object d : data) {
lock.lock();
System.out.println(d);
condition.signalAll();
try {
condition.await(2,TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println("解锁"+d);
}
}
}
}
1
A
解锁1
2
解锁A
B
解锁2
3
解锁B
C
解锁3
解锁C
这时 ,按顺序打印了,执行完,也正常退出,没有卡住主线程。 OK 打完收工
看完不动手等于白学,领会到了T_T