多线程基础

多线程基础总结

一、线程中断

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.两个类似的方法interruptedisInterrupted

  • 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)
        ...
    }
    

二、线程状态

多线程基础_第1张图片
线程状态转换图

BlockedWaiting的区别:

  • Blocked:只有synchronized会导致线程进入Blocked状态,即一个线程试图获取一个对象的锁,而该锁被其他线程持有时,该线程会阻塞。当所有其他线程释放该锁,并且线程调度器允许本线程持有锁时,该线程变为非阻塞状态。
  • WaitingObject.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()

你可能感兴趣的:(多线程基础)