第一章
Happen-Before规则
指令重排的原则:
-
程序顺序原则:一个线程内保证语义的串行性
-
volatile规则:volatile变量的写先发生于读,保证volatile变量的可见性
-
锁规则:解锁unlock必然发生在随后的加锁lock之前
-
传递性:A先于B,B先于C,那么A必然先于C
-
线程的start()先于线程的每一个动作
-
线程的所有操作先于线程的join()发生
-
线程的中断(interrupt())先于被中断线程的代码
-
对象的构造函数执行、结束先于finalize()方法
第二章
1.新建线程
//正确
Thread t1 = new Thread();
t1.start();
//错误
Thread t2 = new Thread();
t2.run();
新建线程需要调用线程的start()方法,方法会新建一个线程并让新建线程执行run()方法,如果直接使用t2.run()方法,会编译通过,也能正常执行,但是它不会新建一个线程,而是在当前线程调用run(),串行执行。
2.终止线程
stop()被标记为废弃,因为该方法太过暴力,会强行终止正在执行的线程,并且释放线程所持有的锁,会引发数据的不一致。
3.中断线程
// 中断线程
public void Thread.interrupt() // 判断是否被中断
public boolean Thread.isInterrupted() // 判断是否被中断,并清除当前中断状态
public static boolean Thread.interrupted()
sleep()方法会抛出InterruptedException中断异常,当在sleep过程中被中断就会抛出,此时会清除中断标记,因此在捕获异常处理时,要手动再次设置中断标记。
Thread t1 = new Thread(){
@Override
public void run() {
while (true){
if(Thread.currentThread().isInterrupted()){
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//中断标记被清除,需要重新设置
Thread.currentThread().interrupt();
}
Thread.yield();
}
}
};
t1.start();
t1.interrupt();
4.wait和notify
这两个方法不存在Thread
类中,还是在Object
里,所有对象都可以调用这两个方法。
public final void wait() throws InterruptedException
public final native void notify()
在一个线程A中调用了obj.wait()方法后,线程A会被阻塞变成等待状态,直到有其他线程调用obj.notify()之后才会继续执行。
wait()方法的调用是会将调用所在线程放到obj对象的等待队列里面,这个队列会保存同一对象调用wait方法的多个线程,当调用obj.notify()之后,会在队列里随机选择
一个线程唤醒继续执行。还有一个notifyAll()的方法,它就会唤醒所有在该队列内的线程。
查看源码可以在wait()和notify()方法的的注释里看到,调用wait的当前线程必须持有对象的监视器,也就是需要被synchronzied
包裹,调用wait和notify之前获取监视器,调用完之后随即释放。这样做是为了不阻碍其他在object等待的线程执行。
wait和sleep的区别是:wait被调用后会释放目标对象的锁,sleep不会释放任何资源。
5.suspend和resume
不推荐使用suspend挂起线程,这是一个已经被标注为废弃的方法,原因是因为suspend在挂起线程时不会释放任何的锁资源,导致其他线程想要访问被占用的锁时都会阻塞住,直到执行了resume操作,才会继续执行。 同时,由于suspend和resume存在时序问题,必须要限制性suspend再执行resume,一旦resume被提前执行了,就会造成死锁。
6.join和yield
join是等待线程结束,一个线程的输入需要依赖其他线程的输出,所以要等他其他线程结果出来再继续执行,这个时候使用join。
//无限等待,一直阻塞线程
public final void join() throws InterruptedException
//限时等待,过时不候
public final synchronized void join(long millis) throws InterruptedException
查看join()源码:
public final synchronized void join(long var1) throws InterruptedException {
long var3 = System.currentTimeMillis();
long var5 = 0L;
if (var1 < 0L) {
throw new IllegalArgumentException("timeout value is negative");
} else {
if (var1 == 0L) {
while(this.isAlive()) {
this.wait(0L);
}
} else {
while(this.isAlive()) {
long var7 = var1 - var5;
if (var7 <= 0L) {
break;
}
this.wait(var7);
var5 = System.currentTimeMillis() - var3;
}
}
}
}
实际上就是在当前线程实例调用wait()方法,执行完成后会调用notifyAll()方法通知其他线程继续执行。
注意:不要在线程上再使用wait和notify,会导致混乱。
yield会让调用线程让出cpu占用,然后后续参与cpu的资源竞争,适合一些优先级低,当前不太需要cpu占用的情况。