java并发编程的艺术-学习4

第四章 Java内存模型

本章着重介绍java并发编程的基础知识,从启动一个线程到线程间不同的通信方式,以及简单的线程池示例。

4.1 线程简介

4.1.1 什么是线程

操作系统调度的最小单元是线程。线程拥有自己的计数器、堆栈、局部变量等属性,能访问共享的内存变量。

4.1.2 为什么使用多线程

更多的处理器核心
更快的响应时间
更好的编程模型

4.1.3 线程优先级

操作系统采用时分的形式调度运行的线程。
线程优先级决定需要分配多少处理器资源(时间片)。优先级越高,分配的时间片越多。
频繁阻塞(休眠或I/O操作)的线程:设置较高优先级
偏重计算(需要较多CPU时间或偏运算)的线程:设置较低优先级
priority:1~10
默认优先级:5
有的操作系统会忽略优先级设置,因此程序正确性不能依赖线程的优先级高低。

4.1.4 线程的状态

状态名称说明
NEW初始状态,线程被构建,但还没调用start()
RUNNABLE运行状态,包括就绪和运行
BLOCKED阻塞状态,表示线程阻塞于锁
WAITING等待状态,表示线程需要等待其他线程的通知或中断
TIME_WAITING超时等待状态,在指定时间自行返回
TERMINATED终止状态,表示线程已经执行完毕

在这里插入图片描述

4.1.5 Daemon线程

是一种支持型线程
Daemon线程的属性需要在线程其他之前设置
不能依靠finally块确保执行关闭或清理资源(因为java虚拟机中不存在非Daemon线程时,Java虚拟机会退出。
Thread.setDaemon(true)设置线程为Daemon线程

4.2 启动和终止线程

4.2.1 构造线程

初始化构造线程对象:线程所属的线程组、优先级、是否Daemon线程等
新构造的线程对象,由其parent线程进行空间分配,child继承了parent的属性:是否Daemon、优先级、加载资源的contextClassLoader、ThreadLocal等

4.2.2 启动线程

初始化后,调用start()

4.2.3 中断

中断标识位属性
isInterrupted()
Thread.interrupted()
抛出InterruptedException后,中断标识位被清除

4.2.4 过期的suspend()、resume()、stop()

suspend():调用后,线程不会释放资源(锁),而是占着资源进入睡眠,容易引发死锁问题。
stop():终结一个线程时不会保证资源正常释放,导致程序可能工作在不确定状态下。
可以用等待/通知机制替代

4.2.5 安全地终止线程

通过标识位或者中断操作的方式终止线程,使线程在终止时有机会清理资源,更安全

4.3 线程间通信

4.3.1 volatile和synchronized

volatile修饰成员变量,保证所有线程对变量访问的可见性。共享内存。
synchronized修饰方法、代码块,保证线程对变量访问的可见性、排他性。
同步块的实现monitorenter和monitorexit指令,同步方法实现修饰符ACC_SYNCHRONIZED(隐式)。本质是对象的监视器(monitor)。
任意线程对Object的访问,首先获得Object的监视器,获取失败,则进入同步队列,线程状态变为BLOCKED;当访问Object的前驱释放锁,则该释放操作唤醒阻塞在同步队列中的线程,重新尝试获取监视器。

4.3.2 等待/通知机制

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

 调用wait()、notify()、notifyAll()注意细节:
1)需先调用对象加锁(如synchronized)
2)调用wait()后,线程状态由RUNNING变为WAITING,并将当前线程放置到对象的等待队列
3)notify()/notifyAlll()调用后,等待线程依旧不会从wait()返回,需要调用notify()/notifyAll()的线程释放锁之后,等待线程才有机会从wait()返回
4)notify()将等待队列中的一个线程移到同步队列;notifyAll()将等待队列中所有线程全部移到同步队列,被移动的线程由WAITING变为BLOCKED
5)从wait()方法返回前提是,获得调用对象的锁

4.3.3 等待/通知的经典范式

等待:
1)获得对象的锁
2)如果条件不满足,那么调用对象的wait()方法,被通知后仍要检查条件
3)条件满足则执行对应的逻辑
通知:
1)获得对象的锁
2)改变条件
3)通知等待在对象上的线程

4.3.4 管道输入/输出流

管道输入/输出流和普通的文件输入/输出流或者网络输入/输出流不同之处在于,它主要用于线程之间的数据传输,而传输的媒介是内存。
4种具体实现:PipedOutputStream、PipedInputStream、PipedReader、PipedWriter

out.connect(in)

4.3.5 Thread.join()的使用

当前线程等待thread线程终止之后才从thread.join()返回。保证线程执行顺序。

4.3.6 ThreadLocal的使用

ThreadLocal,即线程变量,是一个以ThreadLocal对象为键、任意对象为值的存储结构。附在线程上,可以根据ThreadLocal对象查询到绑定在这个线程上的值。
理解参考: https://www.jianshu.com/p/98b68c97df9b

4.4 线程应用实例

4.4.1 等待超时模式

4.5 本章小结

启动和终止线程以及线程状态,线程通信方式,示例。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值