1 System.out.println 导致线程停止
public class ThreadStop {
public static boolean stop;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
int i =0;
while (!stop) {
i++;
}
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
stop = true;
}
}
如上代码,我们都知道,因为 stop的值更新在主线程,子线程的值不是最新的,所以会循环不止,但是我们加上一行代码再试试
public class ThreadStop {
public static boolean stop;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
int i =0;
while (!stop) {
i++;
System.out.println(" i的值 "+i);
}
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
stop = true;
}
}
我们会发现线程停止了,问什么?有人说是System.out.println 源码里有synchronized 关键字,会改变stop 的值,其实不然,Jvm的CPU会尽力保证变量值的更新,但是它不是100%成功的,只能尽自己能力,如果CPU一直没有空闲出来,它就不会进行更新,但是一旦CPU空闲了,就有机会去更新。所以关键是让CPU获取时间片,另外我们也可以在while 中进行 sleep,也可以实现线程终止
2 如何理解 sleep 和wait
首先我们提几个问题
1.sleep 会放弃线程占有的锁吗?
2. wait 调用之前需要占有对象的锁吗? 如果需要, namewait之后会放弃对象占有的锁吗?
2.1 等待池 和 锁池
先介绍2个概念
锁池:当多个线程竞争对象A某个synchronized方法时,只有一个线程会占有锁,其他线程都需要等待,这时候等待的线程就会进入对象A 的锁池中等待池:假如线程T调用了线程A的wait方法,T就会释放该对象的锁,同时进入对象A的等待池,如果其他对象notify或者notifyAll被调用,name对象A的等待池中的线程(1个或者全部,取决于notify还是notifyAll)会进入 锁池,伺机争夺锁的拥有权
所以开始的答案是
1.sleep 不会放弃锁,即便休眠仍然持有
2. 只有占有锁的线程,才有机会调用 对象的wait方法,调用之后,将会放弃其占有锁,并进入等待池,如果一个没有占有锁的线程调用 wait 会抛出异常