多线程基础总结
一、线程中断
interrupt
方法用来请求终止线程。
1. interrupt
置位中断标志位
当对一个线程调用interrupt
方法时,线程的中断标志位被置位,表示请求终止线程。
// 线程将中断作为终止程序的请求
Runnable r1 = () -> {
try {
Thread.sleep(1000); // 阻塞
// 正常情况下检测中断标志位
while (!Thread.currentThread().isInterrupted()) {
// has work to do
}
} catch (InterruptedException e) {
// 线程在阻塞的时候被中断
} finally {
// 清除资源
}
// 退出程序
};
2. 如果线程被阻塞,调用interrupt
方法,阻塞调用会被InterruptedException
异常中断。
此时,应捕获InterruptedException
异常。
// 阻塞的时候被中断,会清除中断标识位,并抛出中断异常
Runnable r2 = () -> {
try {
while (true) {
// has work to do
Thread.sleep(1000); // 睡眠的时候产生中断
}
} catch (InterruptedException e) {
// 线程在阻塞的时候被中断
} finally {
// 清除资源
}
// 退出程序
};
3.两个类似的方法interrupted
与isInterrupted
-
interrupted
方法为静态方法,检测线程是否被中断,并清除中断标志位。 -
isInterrupted
方法为实例方法,用来检测线程的中断状态,但不清除中断标志位。
4.使用不当及纠正
void mySubTask() {
...
try {sleep(delay)}
catch (InterruptedException e) {} // 被忽略
}
上述代码中的中断异常不应被忽略,有以下两种选择:
-
在catch中调用Thread.currentThread().interrupt()来设置中断状态。调用者可以来检测。
void mySubTask() { ... try {sleep(delay)} catch (InterruptedException e) { Thread.currentThread().interrupt(); } // 被忽略 }
-
抛出
InterruptedException
异常,不try
捕获异常。上层可以捕获该异常。void mySubTask() throws InterruptedException{ ... sleep(delay) ... }
二、线程状态

Blocked
和Waiting
的区别:
-
Blocked
:只有synchronized
会导致线程进入Blocked
状态,即一个线程试图获取一个对象的锁,而该锁被其他线程持有时,该线程会阻塞。当所有其他线程释放该锁,并且线程调度器允许本线程持有锁时,该线程变为非阻塞状态。 -
Waiting
:Object.wait()
导致线程进入Waiting
状态,Waiting
线程被其他线程调用Object.notify()
唤醒之后,重新获取对象上的锁的时候(但没获取到)也会进入Blocked
状态。被唤醒的线程需要重新获取到对象的锁才能恢复执行。
三、锁对象
1.可重入锁ReentrantLock
模板代码:�
Lock myLock = new ReentrantLock();
myLock.lock(); // 互斥、可重入
try {
// 临界区
} finally {
myLock.unlokc();
}
2.条件Condition
**`Lock`下更加细粒度的并发控制.**
`Condition`用来控制、管理那些已经获得了一个锁,但是却因为不满足条件而不能做有用工作的线程。一个锁对象可以有一个或多个条件对象。
private Lock bankLock = new ReentrantLock();;
private Condition sufficientFunds = bankLock.newCondition(); // 足够的资金
// sufficientFunds.await(); ---> sufficientFunds.signalAll();
public void transfer(int from, int to, int amount) {
bankLock.lock();
try {
while(account[from] < amount) {
sufficientFunds.await(); // 金额不足,阻塞
}
// transfer funds
sufficientFunds.signalAll(); // signalAll()
} finally {
bankLock.unlock();
}
}
四、synchronized
关键字
Java
中的每一个对象都有一个内部锁。如果一个方法用synchronized
声明,则对象的锁将保护整个方法。
public synchronized void method() {
// method body
}
// 等价于
public void method() {
this.intrinsicLock.lock();
try {
// method body
} finally {
this.intrinsicLock.unlock();
}
}
内部对象锁只有一个条件,调用wait()
添加一个线程到条件的等待集中,notifyAll/notify()
方法解除等待线程的阻塞状态。
intrinsicCondition.await() ---- wait()
intrinsicCondition.signalAll() ---- notifyAll()
网友评论