Java并发编程的艺术-笔记2

并发编程的艺术-笔记2


1.线程简介

现代操作系统调度的最小单位是线程,也叫轻量级进程,每个进程可创建多个进程,每个线程都有各自的计数器、堆栈和局部变量等属性,并且能够访问共享变量。处理器在这些线程上高速切换,让使用者感觉到这些线程在同时执行。

线程优先级:决定线程分配处理器资源多少的属性,设置时,针对频繁阻塞(休眠或I/O操作)的线程需要设置较高优先级,而偏重计算的线程则设置较低优先级。在不同操作系统上会有差异,有的操作系统甚至会忽略线程优先级的设定。

Daemon线程:守护线程,主要被用作程序中后台调度以及支持行工作。
通过Thread.setDaemon(true)设置守护线程,且Daemon需要在启动线程前设置。
虚拟机中不存在非Daemon线程时就会退出。虚拟机退出时Daemon线程不能通过finally块中的内容来确保执行关闭或清理资源的逻辑。

2.线程的启动和终止

1.线程的启动:线程对象初始化完成后调用start()方法就能启动线程。
2.中断:可以理解为线程的一个标识位属性,通过调用线程的interrupt()方法设置该标识。方法抛出InterruptedException之前,虚拟机会先将线程的中断标识清除。使用标识位和中断的方式能够使线程在终止时有机会去清理资源,这种方法显得更安全和优雅。

3.线程间通信

1)volatile和synchronized关键字
volatile修饰字段,告知线程对变量的访问要从共享内存内获取,而对它的改变必须同步刷新回共享内存,保证所有线程对变量访问的可见性。
synchronized确保多个线程在同一时刻,只能有一个线程处于方法和同步块中,保证了线程对变量访问的可见性和排他性。

任意一个对象都有自己的监视器,当这个对象由同步块或者这个对象的同步方法调用时,执行方法的线程必须先获取到监视器(执行该方法)的线程将会被阻塞在同步块和同步方法的入口处,进入BLOCKED状态。当获得了锁的线程释放了锁,则钙释放操作唤醒阻塞在同步队列中的线程,使其重新尝试对监视器的获取。
Java并发编程的艺术-笔记2_第1张图片
对象、监视器、同步队列和执行线程之间的关系

2)等待/通知机制
等待/通知机制依托于同步机制,目的是确保等待线程从wait()方法返回时能够感知到通知线程对变量做出改变。
等待/通知机制的经典范式:
等待方:1.获取对象的锁。2.如果执行条件不满足,那么调用对象的wait()方法,被通知后仍要检查条件。3.条件满足则执行对应的逻辑。
通知方:1.获得对象的锁。2.改变条件。3.通知所有等待在对象上的线程。

3)管道输入输出流
主要用于线程之间的数据传输,而传输的媒介为内存。
包括如下的具体实现:PipeOutStream、PipeInputStream、PipedReader、PipedWriter,前两种面向字节,后两种面向字符。
使用时必须将输入输出流通过out.connect(in)方法进行对接,否则抛出IOException。

4)Thread.join()
如果一个线程A执行了thread.join()语句,其含义是:当前线程A等待thread线程终止之后才从thread.join()返回。
join()方法的逻辑结构和等待通知机制的经典范式相同。

5)ThreadLocal
即线程变量,是一个以ThreadLocal对象为键、任意对象为值的存储结构。这个结构被附带在线程上,也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的一个值。

4.线程池技术

线程池预先创建了若干数量的线程,并且不能由用户直接对线程的创建进行控制,在这个前提下重复使用固定或较为固定的数目来完成任务的执行。
这样做的好处是,一方面,消除了频繁创建和消亡线程的系统资源开销,另一方面,面对过量任务的提交能够平缓的劣化。
一个简单的线程池接口的定义:

public interface ThreadPool<Job extends Runable> {
     void execute(Job job);
     void shutdown();
     void addWorkers(int num);
     void removeWorker(int num);
     int getJobSize();
}

你可能感兴趣的:(并发)