JUC概述
1. 什么是JUC ?
java.util.concurrent工具包的简称,从jdk1.5开始出现
2. 线程和进程的概念
1.什么是进程什么是线程?
1.进程:指的是系统中正在运行的一个应用程序; ------资源分配的最小单位
2.线程:系统再分配处理器时间资源的基本单位; ------程序执行的最小单位
2. 线程的状态
1.新建状态/就绪状态 ——创建还未启动
2.运行状态 ——使用start()方法调用
3.阻塞状态 ——没有抢到被锁住的资源,被阻塞
4.等待状态 ——使用wait()方法进入阻塞等待状态
5.计时等待状态/超时等待 —— sleep()网上有叫计时也有叫超时,其实意思就是在等待一定时间之后自动唤醒
6.终止
3.wait和sleep的区别
1.sleep是Thread的静态方法,wait是Object的方法, 任何实例对象都可以直接调用
2.sleep不会释放锁,wait会释放锁。
3.使用范围:wait,notify和notifyAll只能在同步代码块里面使用,而sleep可以在任何地方使用
4.sleep必须要捕获异常,wait不用
4.并发和并行
1. 并行:多项工作一起执行,最后汇总
2. 并发:多个线程同时抢占同一份资源
5.管程—Monitor监视器
1.是一种同步机制,保证在同一时刻只有一个线程访问被保护数据的代码
2.JVM同步基于进入和退出,使用管程对象实现——现持有管程对象去访问,别的进程没有管程对象就不能访问,要等这个线程释放管程
6.用户线程和守护线程
1.用户线程:自定义线程
2.守护线程:特殊线程运行在后台,比如垃圾回收,会一直等待到用户的主线程结束比如main3.可以同setDaemon设置用户线程和守护线程, 默认false用户线程
3.创建线程的几种方法
1.继承Thread方法:
1.重写run方法
2.实现Runable接口
1.实现run方法
3.实现Callable接口
1. FutureTask 未来任务 原理:
1. 需要使用FutureTask实现类接收参数,然后使用Thread启动线程
2. 什么是未来任务?
1. Callable会返回一个结果,下次同一个线程再去执行相同任务的时候不需要等待,之间获得结果
2. 他会等所有Callable创建的线程完成在做一个汇总输出
4. Runnable接口和Callable接口的区别
1. Runnable接口实现的是Run()方法,Callable规定的方法是call()。
2. Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
3. call方法可以抛出异常,run方法不可以
5.线程池(在下面)
1.创建线程池的方式
1.通过Executors工厂方法创建
//:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待;
Executors.newFixedThreadPool(2);
//:创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程
Executors.newCachedThreadPool();
//:创建单个线程数的线程池,它可以保证先进先出的执行顺序;
Executors.newSingleThreadExecutor();
//:创建一个可以执行延迟任务的线程池;
Executors.newScheduledThreadPool(2);
//:创建一个单线程的可以执行延迟任务的线程池;
Executors.newSingleThreadScheduledExecutor();
//:创建一个抢占式执行的线程池(任务执行顺序不确定)【JDK 1.8 添加】。
Executors.newWorkStealingPool();
2.通过ThreadPoolExecutor new一个原始线程池
2.线程池的七个参数
(1)corePoolSize:线程池中的常驻核心线程数。
(2)maximumPoolSize:线程池能够容纳同时执行的最大线程数,此值大于等于1。
(3)keepAliveTime:多余的空闲线程存活时间,当空间时间达到keepAliveTime值时,多余的线程会被销毁直到只剩下corePoolSize个线程为止。
(4)unit:keepAliveTime的单位。
(5)workQueue:任务队列,被提交但尚未被执行的任务。
(6)threadFactory:表示生成线程池中工作线程的线程工厂,用户创建新线程,一般用默认即可。
(7)handler:拒绝策略,表示当线程队列满了并且工作线程大于等于线程池的最大显示数(maxnumPoolSize)时如何来拒绝请求执行的runnable的策略。
3.线程池的流转方式:
1. 一个池里面有两个线程常驻(corePoolSize:常驻核心线程数量),如果来了两个任务需要处理,就由这两个常驻线程进行处理
2. 如果这个时候又来了两个任务,就把任务丢进任务队列(workQueue)里面进行等待。
3.如果来了很多任务导致任务队列爆满,那么就由线程工厂(threadFactory)创建新的线程开始处理任务。
4.此时创建的线程达到了线程池能够容纳同时执行的最大线程数(maximumPoolSize)此时开始执行拒绝策略(handler),拒绝多出来无法处理的任务。
5.所有任务都处理完了,在等待一定时间之后,关闭多余的线程,以免浪费资源(keepAliveTime:存活时间+unit:keepAliveTime的单位)
线程池:
使用线程池完成异步
1. 设置线程参数创建线程池:
private static final int CORE_POOL_SIZE = 5;
private static final int MAX_POOL_SIZE = 10;
private static final int QUEUE_CAPACITY = 100;
private static final Long KEEP_ALIVE_TIME = 1L;
public static ThreadPoolExecutor executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(QUEUE_CAPACITY),
new ThreadPoolExecutor.CallerRunsPolicy());;
2.创建任务
private static void interfaceOne() {
try {
System.out.println("执行方法One");
Thread.sleep(5000);
System.out.println("执行完毕方法One");
} catch (Exception e) {
System.out.println("执行异常");
}
}
private static void interfaceTwo(){...}
private static void interfaceThree(){...}
3.测试
public static void main(String[] args) {
long a = new Date().getTime();
executor.execute(ThreedTest::interfaceOne);
executor.execute(ThreedTest::interfaceTwo);
executor.execute(ThreedTest::interfaceThree);
long b = new Date().getTime();
interfaceOne();
interfaceTwo();
interfaceThree();
long c = new Date().getTime();
System.out.println("异步执行耗时" + (b - a));
System.out.println("执行耗时" + (c - b));
System.out.println("总耗时" + (c - a));
}
4.结果输出
为什么不是20秒?主线程 5 + 5 + 5 ,然后开了三个线程另外来执行,所以主线程在执行的时候其他线程已经在跑了
锁
1.Synchronized
1.同步实现
1.Synchronized实现同步的基础:Java中的每一个对象都可以作为锁,具体表现以下3种形式。
2.对于普通同步方法,锁是当前实例对象
3.对于静态同步方法,锁是当前类的Class对象
4.对于同步方法块,锁的是Synchronized括号里配置的对象
2.锁的升级--------Synchronized只能升级不能降级
1.偏向锁:
锁对象的对象头里面有个Threadld字段,如果这个字段为空,那么在线程第一次获取锁的时候就会把自己的id写入到ThreadId当中,下次在获取所得时候直接检查threadId中的id是否和自己的ID一致,如果一致就表示以及获取了锁,不用重新获取锁,略过了加锁阶段
2.轻量级锁:
轻量级锁,偏向锁是单线程情况下锁的优化,当有多个线程竞争同一临界资源,这个时候偏向锁就会被撤销,升级成轻量级锁,
3.锁自旋:
4.重量级锁:
2.Lock
3.Lock锁和Synchronized的区别
1. Lock是一个接口,Synchronized是Java的一个关键字,Synchronized是由内置语言实现的。
2. synchronized在发生异常的时候,会自动释放线程占有的锁,Lock如果没用通过unLock()去释放锁,是不会自动释放,很容易导致死锁的产生。
3. 性能问题,由于Synchronized锁的多次优化升级,比如锁的升级,导致使用Sunchronized锁性能是由于lock锁的
4. Lock锁有读锁和写锁,Synchronized没有。
5. Lock可以实现公平锁和非公平锁,实现公平锁在构造函数中传入true就可以实现
4.可重入锁/递归锁
自己也还没搞明白,搞明白再写