Java诞生时就选择了内置对多线程的支持
操作系统运行一个程序时,会为其创建一个进程。
线程是操作系统调度的最小单元,都有各自的计数器、堆栈、局部变量。能访问共享的内存变量。CPU在他们上高速切换,让人感觉在同步执行。
线程会被分到若干时间片,时间片用完了就会发生线程调度。
设置优先级时,对频繁休眠和IO的线程设置高优先级,需要大量计算占用CPU的设置低优先级。
操作系统可以完全不理会Java线程的优先级设定。
4.1.5 Daemon线程
是一种支持型线程,用作程序的后台调度和支持工作
需要在启动线程之前设置
初始化线程在堆内存中等待着运行。
4.2.3 理解线程
一直在sleep的线程,中断后interrupt标志为false(抛出InterruptException前,VM会把线程的标志位被清除了)
一直在运行的线程,中断后interrupt标志为true
4.2.4 过期的suspend(),resume(),stop()
suspend带着锁进入睡眠,容易引发死锁问题,同样,stop在终结一个线程时,不保证线程资源正常释放。
4.2.5 安全地终止线程
interrupt和cancel,通过标识位的方式使终结前释放资源
4.3.1 volatile和synchronized
volatile确保可见性,某线程对字段改变时,其他线程能感知变化。
synchronized使得方法或同步块同一时间内只有一个线程操作
执行的线程必须先获取对象的监视器才能进入同步块或同步方法,获取失败,线程状态变为BLOCKED。
notify通知在对象上等待的线程,从wait上返回。返回的前提是新线程获得了对象的锁(老线程释放锁)
wait:得到其他线程的通知或被中断才会返回,会释放对象的锁
4.3.3 等待/通知的经典范式
等待:
获取对象锁
是否符合条件
执行逻辑
通知:
获取对象锁
改变条件
通知所有等待在对象上的线程
4.3.4 管道输入/输出流
与用于线程间的数据传输,传输媒介是内存
输入输出流要connect起来,先write再print。
4.3.5 thread.join方法
当前线程A调用该方法,等待Thread线程结束后返回。
4.4.2 一个简单的数据库连接池示例
public class ConnectionDriver{
static class ConnectionHandler implements InvocationHandler{
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
if(method.getName().equals("commit")){
TimeUnit.MILLISECONDS.sleep(100);
}
return null;
}
public static final Connection createConnection(){
return (Connection)Proxy.newProxyInstance(ConnectionDriver.class.getClassLoad new Class<>[]{Connection.class},new ConnectionHandler());
}
}
4.4.3 线程池技术及其示例
线程池的本质就是使用了一个线程安全的工作队列连接工作者线程和客户端线程,客户端线程将任务放入工作队列后便返回,而工作者线程则不断地从工作队列上取出工作并执行。当工作队列为空时,所有的工作者线程均等待在工作队列上,当有客户端提交了一个任务之后会通知任意一个工作者线程,随着大量的任务被提交,更多的工作者线程会被唤醒。
SimpleHttpServer建立与客户端连接后,不会处理客户端的请求,而是将其包装成HttpRequstHandler并交由线程池处理。