多线程总结
- Java内存模型
- volatile
- 重排序规则[不允许重排序]
- volatile读+任何操作
- 任何操作+volatile写
- volatile写+volatile读
- 重排序规则[不允许重排序]
- ReentrantLock
- 实现依赖于Java同步器框架AQS
- AQS使用一个整型的volatile变量(命名为state)来维护同步状态
- 这个volatile变量是ReentrantLock内存语义的关键
- concurrent包下的源码通用模式
- 声明共享变量为volatile
- 使用CAS的原子条件更新来实现线程间的同步
- 配合以volatile的读/写和CAS所具有的volatile读和写的内存语义来实现线程之间的通信。
- concurrent包的实现示意图
- DCL方式中singleton被设定为volatile的作用
- 如果没有volatile修饰singleton,多线程情况下可能导致后来的线程读取了一个未初始化完成的singleton对象 [过程2和3重排序了]
- 添加了volatile后,保证了后来的线程读取到的singleton对象一定是初始化完成的。原理是volatile禁止了singleton的引用指向内存空间的操作和初始化操作的重排序。[禁止2和3重排序]
- 一个线程生成一个singleton的过程 1.分配对象的内存空间 2.初始化对象 3.设置singleton引用指向内存地址 4.初次访问singleton对象
- 线程
- 6种状态
- new 构建完成,但未调用start()方法
- runnable 就绪+运行的统称
- blocked 阻塞于锁
- waiting 进入等待状态,需要等待其它线程做一些特定动作(通知or中断)
- time_waiting 超时等待
- terminated 线程执行完毕
- 线程间通信方式
-
volatile和synchronized关键字
-
wait()和notify()、notifyAll()机制
- wait和notify*()方法调用时,需要先对对象加锁
- 调用对象的wait()方法后, 1.线程状态由running变为waiting; 2.当前线程被放到等待队列里面; 3.释放对象的锁。
- notify()将同步队列中的一个线程移到阻塞队列中;notifyAll()方法将同步队列中的所有线程移到阻塞队列中。 ps:线程从同步队列到阻塞队列的状态变化:waiting->blocked
- 处于阻塞队列中的线程在获取对象的监视器Monitor上,具有同等的优先级,且最终只能有一个线程获取成功。
- 处于blocked状态的线程只有获取了对象的Monitor后,才能从wait()方法返回。
-
等待、通知的经典模式[生产者、消费者模式]
-
实质就是wait和notify的使用
-
生产者伪代码
Synchronized(对象) { // 更改条件代码 // 唤醒等待线程 对象.notifyAll(); }
-
消费者伪代码
Synchronized(对象) { while (条件不满足) { 对象.wait(); // 释放对象锁 } // 处理逻辑代码 }
-
-
管道输入、输出流
import java.io.IOException; import java.io.PipedReader; import java.io.PipedWriter; import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException { Scanner scanner = new Scanner(System.in); PipedWriter producter = new PipedWriter(); //1.将信息读入管道 PipedReader consummer = new PipedReader(); //2.从管道读取信息 producter.connect(consummer); //3.绑定 Thread readThread = new Print(consummer); readThread.start(); int resive = 0; try { while ((resive = scanner.nextInt()) != -1) { producter.write(resive); } } catch (Exception e) { } finally { producter.close(); } } static class Print extends Thread { private PipedReader pipedReader; Print(PipedReader pipedReader) { this.pipedReader = pipedReader; } @Override public void run() { int resive = 0; try { while ((resive = pipedReader.read()) != -1) { System.out.println(resive); } } catch (IOException e) { } } }
}
-
Thread.join的使用
- 思想 主线程main执行过程中,启动了一个新的线程thread,并调用了thread.join()方法,则thead必须等待main线程执行完后,才从其join()方法返回。
- 线程终止时,会主动调用notifyAll()方法,通知所有等待在改线程对象上的线程。
- join源码的逻辑结构和生产者/消费者模式一样: 加锁+循环+循环后的逻辑处理。
-
ThreadLocal的使用
-
- 6种状态
- 线程池
-
使用线程池的优势
- 消除了频繁创建和消亡线程的系统资源开销
- 提高相应速度
- 提高线程的可管理性
-
ThreadPoolExecutor构造函数的参数 [4个构造函数]
- 公用
- int corePoolSize
- int maximumPoolSize
- long keepAliveTime 超过核心线程个数的那些空闲线程最长的存活时间
- TimeUnit unit
- BlockingQueue workQueue
- 非公有
- ThreadFactory threadFactory 用于executor创建新线程
- RejectedExecutionHandler handler
- 公用
-
处理流程核心线程池是否满了->任务队列是否满了->线程池是否满了->抛弃策略
-
创建线程池+提交任务+关闭线程池 code
// 方式1 ThreadPoolExecutor executor = new ThreadPoolExecutor(3,10,100,TimeUnit.MILLISECONDS,null); Thread task = new Thread(); executor.execute(task); // 向线程池提交任务.ps:任务类型必须是thread executor.shutdown();// 关闭线程池
// 方式2
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.submit(task);
executorService.shutdown();
-
Executors.newFixedThreadPool方式默认使用LinkedBlockingQueue作为任务队列
-
Executors.newSingleThreadExecutor()方式默认使用LinkedBlockingQueue作为任务队列
-
Executors.newCachedThreadPool()方式默认使用SynchronousQueue作为任务队列
-
阻塞队列的介绍
- ArrayBlockingQueue 基于数组结构的有界阻塞队列,按照FIFO对元素排序
- LinkedBlockingQueue
- 基于链表结构的无界[int最大值]阻塞队列,按照FIFO对元素排序,
- 吞吐量 > ArrayBlockingQueue
- SynchronousQueue
- 一个不存储元素的有界阻塞队列。没有移除操作,则插入操作处于阻塞状态;有移除操作,才进行插入操作。
- 吞吐量 > LinkedBlockingQueue
-
- Executor框架
- java线程和OS内核线程的对应关系:一对一
- java线程启动时,会创建一个OS的线程;当java线程终止时,OS线程也被回收
- 任务的两级调度模型
- Executor框架的使用示意图
- ScheduledThreadPoolExecutor
- 继承自ThreadPoolExecutor
- 用途
- 定期执行任务
- 按给定的延迟执行任务
- 对ThreadPoolExecutor的改进
- 任务队列使用DelayQueue
- 获取任务方式不同 可能添加了放入condition的操作
- 执行周期任务后,增加了额外的处理 从队列取出任务后,修改time的值再放入队列
- DelayQueue中对象RunnableScheduledFutur的属性
- long型time,表示任务要被执行的具体时间
- long型sequenceNumber,表示添加到ScheduledThreadPoolExecutor的序号
- long型period,表示任务执行的间隔周期
- DelayQueue底层实现为PriorityQueue 优先级排序规则:time->sequenceNumber依次升序
- ScheduledThreadPoolExecutor获取任务的过程
- ScheduledThreadPoolExecutor添加任务的过程
- volatile
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。