《Java并发编程的艺术》第四章 Java 并发编程基础

第四章 Java 并发编程基础

4.1 线程

4.1.1 什么是线程

操作系统在运行一个程序时,会创建一个进程,如一个Java程序就对应一个 Java 进程。

一个进程可以创建多个线程,每个线程都拥有各自的计数器、堆栈和局部变量等属性,并且能够访问共享的内存变量。

处理器在这些线程间高速切换,让使用者感觉是在同时运行。

4.1.2 多线程

使用多线程的优势如下:

  1. 更好的利用多处理器核心
  2. 程序运行更快,以获得更快的响应时间
  3. 更好的编程模型

4.1.3 线程优先级

线程优先级决定了线程能够使用处理器的资源多少,默认优先级为5,优先级范围为 1~10.

针对频繁阻塞的(休眠或者 IO操作)线程需要设置较高优先级,而偏重计算(需要较多CPU时间或者偏运算)的线程则设置较低的优先级,确保处理器不会被独占。

4.1.4 线程的状态

Java 线程的六种生命周期:

状态 说明
NEW 初始状态,线程被构建,但是还未调用 start() 方法
RUNNABLE 运行状态,即操作系统中的就绪和运行两种状态
BLOCKED 阻塞状态,表示线程阻塞于锁
WAITING 等待状态,表示当前线程需要等待其他线程做出一些特定动作(通知或中断)
TIME_WAITING 超时等待状态,表示可以在指定时间自动返回的等待状态
TERMINATED 终止状态,表示线程已执行完毕

Java线程状态变迁

4.1.5 Daemon 线程

当Java 虚拟机中不存在 Daemon 线程时,虚拟机将会退出。

通过 Thread.setDaemon(true) 将线程设置为 Daemon 线程。

4.2 启动、终止线程

通过调用线程的 start() 方法启动,随着 run() 方法的执行完毕,线程随之终止。

4.2.1 中断

中断表示一个运行中的线程是否被其他线程进行了中断操作。

中断操作是一种简便的线程间交互方式,而这种交互方式最适合用来取消或停止任务。

4.2.2 安全地终止线程

通过标识位或者中断操作的方式,能够使线程在终止时有机会去清理资源,而不是武断地将线程停止。

通过标识位和中断来停止线程:

public class TestRunner implements Runnable {
    private long i;
    private volatile boolean on = true;
    @Override
    public void run() {
        while(on && !Thread.currentThread().isInterrupted()){
            i++;
        }
    }

    public void cancel(){
        on = false;
    }
}

4.3 线程间通信

Java 支持多个线程同时访问一个对象或者对象的成员变量,由于每个线程可以拥有这个变量的拷贝,所以程序在执行过程中,各线程看到的变量并不一定是最新的。

4.3.1 volatile 和 synchronized 关键字

volatile 关键字:用来修饰的变量,可以使访问该变量的线程均从共享内存中获取。且对共享变量的修改,必须同步刷新回共享内存中。但是过多地使用volatile 会降低程序执行的效率。

synchronized 关键字:用来修饰方法或者同步块,确保多个线程在同一时刻,只能有一个线程处于方法或者同步块中,保证了线程对变量访问的可见性和排他性。

4.3.2 等待/通知机制

等待/ 通知机制,是指一个线程A 调用了对象O 的wait() 方法而进入等待状态。线程B 调用了对象O 的notify()或notifyAll() 方法,线程A 收到通知后从对象O的wait() 方法返回,进而执行后续操作。

等待通知的经典范式:

等待方(消费方):

  1. 获取对象的锁
  2. 如果条件不满足,则调用对象的wait()方法,被通知后仍要检查条件
  3. 条件满足则执行对应的逻辑
synchronized(对象){
    while(条件不满足){
        对象.wait();
    }
    处理逻辑
}

通知方(生产者):

  1. 获得对象的锁
  2. 改变条件
  3. 通知所有等待在对象上的线程
synchronized(对象){
    改变条件
    对象.notifyAll();
}

4.3.3 Thread.join()

如果一个线程 A 执行了 thread.join() 语句,其含义是:当前线程 A 等待 thread 线程终止之后才从 thread.join() 返回。

4.4 线程应用实例

4.4.1 等待超时模式

调用一个方法后,如果在等待时间内得到结果则立即返回,否则返回默认结果。

// 伪代码:
public synchronized Object get(long mills) throws InterruptedException {
    long future = System.currentTimeMills() + mills;
    long remaining = mills;

    while((result == null) && remaining > 0){
        wait(remaining);
        remaining = future - System.currentTimeMills();
    }

    return result;
}

4.4.2 简单的数据库连接池

4.4.3 基于数据库连接池的Web服务器

文章作者: koral
文章链接: http://luokaiii.github.io/2019/06/11/读书笔记/《Java并发编程的艺术》/4.Java并发编程基础/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自