【书】【Java并发编程之美】要点记录
1 wait 函数
当一个线程调用一个共享变量的 wait() 方法时,该调用线程会被阻塞挂起,直到发生 下面几件事情之一才返回:
(1)其他线程调用了该共享对象的 notify() 或者 notifyAll() 方法;
(2)其他线程调用了该线程的 interrupt() 方法,该线程抛出 InterruptedException 异常返回。
另外需要注意的是,如果调用 wait() 方法的线程没有事先获取该对象的监视器锁,则 调用 wait() 方法时调用线程会抛出 IllegalMonitorStateException 异常。
那么一个线程如何才能获取一个共享变量的监视器锁呢?
(1)执行 synchronized 同步代码块时,使用该共享变量作为参数。
synchronized(共享变量){ //doSomething }
(2)调用该共享变量的方法,并且该方法使用了 synchronized 修饰。
synchronized void add(int a,int b){ //doSomething }
2 线程中断
void interrupt() 方法 :中断线程,例如,当线程 A 运行时,线程 B 可以调用线程 A 的 interrupt() 方法来设置线程 A 的中断标志为 true 并立即返回。设置标志仅仅是设 置标志,线程 A 实际并没有被中断,它会继续往下执行。如果线程 A 因为调用了 wait 系列函数、join 方法或者 sleep 方法而被阻塞挂起,这时候若线程 B 调用线程 A 的 interrupt() 方法,线程 A 会在调用这些方法的地方抛出 InterruptedException 异常而返回。
boolean isInterrupted() 方法 :检测当前线程是否被中断,如果是返回 true,否则返 回 false。
public boolean isInterrupted() { return isInterrupted(false); }
boolean interrupted() 方法 :检测当前线程是否被中断,如果是返回 true,否则返 回 false。与 isInterrupted 不同的是,该方法如果发现当前线程被中断,则会清除中断标志,并且该方法是 static 方法,可以通过 Thread 类直接调用。另外从下面 的代码可以知道,在 interrupted() 内部是获取当前调用线程的中断标志而不是调用 interrupted() 方法的实例对象的中断标志。
public static boolean interrupted() { return currentThread().isInterrupted(true); }
private native boolean isInterrupted(boolean ClearInterrupted);
3 死锁
死锁的产生必须具备以下四个条件。
互斥条件 :指线程对已经获取到的资源进行排它性使用,即该资源同时只由一个线程占用。如果此时还有其他线程请求获取该资源,则请求者只能等待,直至占有资源的线程释放该资源。
请求并持有条件:指一个线程已经持有了至少一个资源,但又提出了新的资源请求,而新资源已被其他线程占有,所以当前线程会被阻塞,但阻塞的同时并不释放自己已经获取的资源。
不可剥夺条件 :指线程获取到的资源在自己使用完之前不能被其他线程抢占,只有在自己使用完毕后才由自己释放该资源。
环路等待条件 :指在发生死锁时,必然存在一个线程—资源的环形链,即线程集合{T0,T1,T2,…,Tn} 中的 T0 正在等待一个 T1 占用的资源,T1 正在等待 T2 占用的资源,……Tn 正在等待已被 T0 占用的资源。
要想避免死锁,只需要破坏掉至少一个构造死锁的必要条件即可,但是学过操作系统的读者应该都知道,目前只有请求并持有和环路等待条件是可以被破坏的。