问题描述
按理说,当第一个线程(前面)的synchronized获得对象锁了以后,第二个线程(后面)就只能等待,当第一个线程添加完list,执行demo.list.notify()方法只会通知等待队列中的第一个相关线程,根据输出结果看是去唤醒第二个线程,这个时候第二个线程执行添加list。问题是:但是notify()方法不会释放锁,且第一个线程先获取到锁,那么第二个线程是应该是无法先获取到锁的,是如何进入wait()方法,等待第一个线程获取的
案例代码
public class ThreadCommunication {
private final List<Integer> list =new ArrayList<>();
public static void main(String[] args) {
ThreadCommunication demo =new ThreadCommunication();
new Thread(()->{
for (int i=0;i<10;i++){
synchronized (demo.list){
if(demo.list.size()%2==1){
try {
demo.list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
demo.list.add(i);
System.out.print(Thread.currentThread().getName());
System.out.println(demo.list);
demo.list.notify();//不会释放锁
}
}
}).start();
new Thread(()->{
for (int i=0;i<10;i++){
synchronized (demo.list){
if(demo.list.size()%2==0){
try {
demo.list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
demo.list.add(i);
System.out.print(Thread.currentThread().getName());
System.out.println(demo.list);
demo.list.notify();
}
}
}).start();
}
}
假设第一个线程先抢到锁执行,因为不会满足if(demo.list.size()%2==1)的,所以不会wait,就会执行demo.list.add(i)。离开了synchrnized(demo.list){}的作用域(也就是花括号)锁就会自动释释放,demo.list.notify();是唤醒wait的线程抢锁的,所以此时线程1和线程2都有机会再抢锁。假如还是线程1先抢到锁,那线程1就会满足if(demo.list.size()%2==1)而wait,让出锁来让线程2执行;假如是线程2抢到锁,线程2因为不满足if(demo.list.size()%2==0)而继续添件元素demo.list.add(i),然后调用demo.list.notify唤醒线程1一起抢锁(_被唤醒的线程是从wait以后的代码继续执行的,所以不会重新判断if条件,所以此时就算if条件不满足,线程也继续执行后面的代码_)。。。依次反复执行,直到每个线程的for循环结束
你把if(demo.list.size()%2==1)改成while(demo.list.size()%2==1)能解决上面的不重新判断if的问题,同样线程2的if(demo.list.size()%2==0)也要改成while