package com.bjsxt.base.conn008;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
/**
 * @author wangyang
 *
 */
public class ListAdd2 {
private volatile static List list = new ArrayList();

public void add(){
list.add("wangyang");
}
public int size(){
return list.size();
}

public static void main(String[] args) throws InterruptedException {


final ListAdd2 list2 = new ListAdd2();
final Object lock = new Object();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
synchronized (lock) {
System.out.println("t1启动..");
for(int i = 0; i <10; i++){
list2.add();
System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");
Thread.sleep(500);
if(list2.size() == 5){
System.out.println("已经发出通知..");
lock.notify();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} }
}, "t1");

Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(list2.size());
synchronized (lock) {
System.out.println("t2启动.."); if(list2.size() != 5){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止..");
throw new RuntimeException();
}
}
}, "t2");

t2.start();
Thread.sleep(1000);

t1.start();
}

}当list2.size==5时,唤醒t2线程,然后t1执行完后,t2拿到锁,可是此时list2.size已经是10了,为什么还是会执行下面的抛异常的代码呢?请各位大神指教一下,多谢

解决方案 »

  1.   

    根据你给出的代码我试着DEBUG运行了两次,那么输出结果图如下:从图中我们可以看出首先输出的t1启动,然后是t2输出当前list的大小为0;
    接着输出了t1添加元素,然后发出通知,继续添加到结束释放锁;
    再下来是t2获取到锁然后启动并判断是list的大小为5,因为这个时候不是5所以会发出lock.wait()执行,然后一直等待。并不会执行之后的程序,所以就结束了。
    然后我直接运行,而不是debug模式,则输出如下:从图中明显可以看出首先是t2输出了list的大小为0;然后显示t2启动,因为这个时候t2拿到了锁,去判断,发现list的大小不是5所以会等待并释放锁;
    然后我们看到t1获得锁并开始启动,然后添加元素发出通知,然后继续添加到结束,释放锁;
    然后t2会获取到锁,那么这个时候,是否list的大小是5的判断并不会再次执行,因为你用的是if判断,而且他已经执行过了,所以就会直接执行之后的代码输出了:
    当前线程t2收到了通知停止线程,并且接着抛出了异常。
    因为t2的判断已经在第一次获得锁就执行了,第二次获得锁则直接运行之后的代码,所以会执行输出和抛出异常。
    这理解你应该是和我图2得到的相同的结果,所以你看到了异常输出。
    如果答案满意,望采纳。