JUC编程
一 、创建线程
1.实现Runable接口 (没有返回值)
new Thread(new Runnable() {
@Override
public void run() {
}
},"thread name").start();
//简洁写法
new Thread(() -> {}, "A").start();
2.实现Callable()接口 (有返回值)
package com.lh.juc;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class CallableTak implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("callable come in");
return 1024;
}
}
public class CallableDemo {
public static void main(String[] args) throws Exception {
FutureTask task = new FutureTask(new CallableTak());
new Thread(task, "A").start();
//获取返回值
task.get();
}
}
二. syschronized 锁
1.作用域
- 作用在实例方法上:锁类的是实例对象
- 作用在静态方法上:锁住的是类对象
- 作用在实例对象的代码块:锁住的是实例对象
- 作用在class对象:锁住的是类对象
- 任意实例的对象:锁住的是实例对象的Object
能锁 但是锁定粒度太大了 不够灵活`
public synchronized void saleTicket() {
}
}
三. Locks锁
更加灵活
private Lock lock = new ReentrantLock();
public void saleTicket()
//加锁
lock.lock();
try {
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
}
}
四、线程之间的通信
1.wait() - Object类的方法
使对象释放共享锁,从运行状态退出,进入等待的队列,直到再一次被唤醒 重新进入竞争锁的状态。
2.notify() - Object类的方法
随机唤醒等待队列中等待同一共享资源的一个线程,并使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知一个线程。
3.notifyAll() - Object类的方法
使所有正在等待队列中等待同一共享资源的全部线程退出等待队列,进入可运行状态。此时,优先级最高的那个线程最先执行,但也有可能是随机执行,这取决于JVM虚拟机的实现。
4.sleep() - Thread的方法
使线程进入等待状态,但是不会释放对象锁也不会让出CPU,持续保持对该对象的监视状态,指定时间结束后自动唤醒。可以使用interrupt 强行打断。
5. lock.lock() - Lock接口方法
6.await() -Lock CondItion接口的方法 - 对标 wait()
7.signal() -Lock CondItion接口的方法 - 对标 notify()
8.signalAll() -Lock CondItion接口的方法 - 对标 notifyAll()
9.Demo (synchronized 版)
如果没有使用synchronized 或者其他锁 锁住当前对象 也就相当于没有当前线程不是当前对象的占有者 不能使用 wait notifyAll 等方法会抛出 IllegalMonitorStateException 异常
例子1:单生产 单消费 (一个线程生产,一个线程消费)
package com.lh.juc;
/**
* 线程之间的通信
* <p>
* 练习:两个线程操作一个变量 初始值为 分别进行加减 进行十次以后还是0
* 1.创建资源类 也就是业务逻辑处理类
* 2。创建线程操作资源类
*/
public class ThreadWaitNotifyDemo {
public static void main(String[] args) {
DoSomeThing doSomeThing = new DoSomeThing();
new Thread(() -> {
try {
doSomeThing.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "A").start();
new Thread(() -> {
try {
for (int i = 0; i < 9; i++) {
doSomeThing.decrement();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "B").start();
}
}
class DoSomeThing {
private int num = 0;
public synchronized void increment() throws InterruptedException {
//判断
if (num != 0) {
this.wait();
}
//干活
num++;
System.out.println(Thread.currentThread().getName() + ":" + num);
//通知
// 如果没有使用synchronized 或者其他锁 锁住当前对象 也就相当于没有当前线程不是当前对象的占有者 不能使用 wait notifyAll 等方法
// 会抛出 IllegalMonitorStateException 异常
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
//判断
if (num == 0) {
//线程进入等待状态 notifyAll 唤醒
this.wait();
}
//干活
num--;
System.out.println(Thread.currentThread().getName() + ":" + num);
//通知
this.notifyAll();
}
}
例子2:多生产 多消费
1.存在问题-虚拟唤醒
线程间进行通信(wait、notify…)的场景下不能用if 不能用if 不能用 if 必须用 while
private int num = 0;
public synchronized void increment() throws InterruptedException {
//判断
if (num != 0) {
//假如此时 num=1
//A1线程在wait()之前中断
this.wait();
}
//num=1 A1再次唤醒的时候不会再走if A2此时进来的已经完成了+1操作 A1不会重新判断 num!=0 (if判断只会走一次)
// A1直接往下num++ =>虚假唤醒s
num++;
System.out.println(Thread.currentThread().getName() + ":" + num);
案例:if判断与可能会导致虚假唤醒 因为 if 只会判断一次 此时if 判断里边的 wait在线程第二次唤醒的情况下并不会执行。
2.解决
用while解决 线程被重新唤醒后不会跳过while方法判断往下走。
package com.lh.juc;
/**
* 线程之间的通信
* <p>
* 练习:两个线程操作一个变量 初始值为 分别进行加减 进行十次以后还是0
* 1.创建资源类 也就是业务逻辑处理类
* 2。创建线程操作资源类
*/
public class ThreadWaitNotifyDemo {
public static void main(String[] args) {
DoSomeThing doSomeThing = new DoSomeThing();
new Thread(() -> {
try {
for (int i = 0; i < 9; i++) {
doSomeThing.increment();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "A").start();
new Thread(() -> {
try {
for (int i = 0; i < 9; i++) {
doSomeThing.decrement();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "B").start();
new Thread(() -> {
try {
for (int i = 0; i < 9; i++) {
doSomeThing.increment();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "C").start();
new Thread(() -> {
try {
for (int i = 0; i < 9; i++) {
doSomeThing.decrement();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "D").start();
}
}
class DoSomeThing {
private int num = 0;
public synchronized void increment() throws InterruptedException {
//判断
while (num != 0) {
this.wait();
}
//干活
num++;
System.out.println(Thread.currentThread().getName() + ":" + num);
//通知
// 如果没有使用synchronized 或者其他锁 锁住当前对象 也就相当于没有当前线程不是当前对象的占有者 不能使用 wait notifyAll 等方法
// 会抛出
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
//判断
while (num == 0) {
//线程进入等待状态 notifyAll 唤醒
this.wait();
}
//干活
num--;
System.out.println(Thread.currentThread().getName() + ":" + num);
//通知
this.notifyAll();
}
}
10.锁现象
1.标准访问
package com.lh.juc;
class Phone{
public synchronized void sendEmail(){
System.out.println("send email");
}
public synchronized void sendSMS(){
System.out.println("send SMS");
}
}
/**
* 1.标准访问 先打印邮件还是短信 => 不一定啊 线程star后 由CPU来调用 =>先打印邮件
*/
public class Lock8 {
public static void main(String[] args) throws Exception {
Phone phone = new Phone();
new Thread(phone::sendEmail,"A").start();
Thread.sleep(200); //保证A先启动
new Thread(phone::sendSMS,"B").start();
}
}
2.同一个对象
package com.lh.juc;
import java.util.concurrent.TimeUnit;
class Phone {
public synchronized void sendEmail() {
try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("send email");
}
public synchronized void sendSMS() {
System.out.println("send SMS");
}
}
/**
* <p>
* 2.邮件方法暂停4秒 先打印邮件还是短信 => 邮件 => 同一个对象使用的是同一个锁的资源 线程会竞争同一把锁 先到的
*/
public class Lock8 {
public static void main(String[] args) throws Exception {
Phone phone = new Phone();
new Thread(phone::sendEmail, "A").start();
Thread.sleep(200); //保证A先启动
new Thread(phone::sendSMS, "B").start();
}
}
3.新增一个普通方法
package com.lh.juc;
import java.util.concurrent.TimeUnit;
class Phone {
public synchronized void sendEmail() {
try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("send email");
}
public synchronized void sendSMS() {
System.out.println("send SMS");
}
public void hello(){
System.out.println("hello");
}
}
/**
* 3.新增一个普通hello()方法 新打印邮件还是 hello() => 普通方法不会竞争锁 会直接执行
*/
public class Lock8 {
public static void main(String[] args) throws Exception {
Phone phone = new Phone();
new Thread(phone::sendEmail, "A").start();
Thread.sleep(200); //保证A先启动
new Thread(phone::hello, "B").start();
}
}
4.创建一个新对象
package com.lh.juc;
import java.util.concurrent.TimeUnit;
class Phone {
public synchronized void sendEmail() {
try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("send email");
}
public synchronized void sendSMS() {
System.out.println("send SMS");
}
public void hello(){
System.out.println("hello");
}
}
/**
* 4.两个Phone对象 phone1 phone2 先打印邮件还是短信 =>先打印SMS =>
两个不同的对象使用的锁资源不一样,线程先调度的先执行,没有锁竞争。
*/
public class Lock8 {
public static void main(String[] args) throws Exception {
Phone phone = new Phone();
Phone phone2 = new Phone();
new Thread(phone::sendEmail, "A").start();
Thread.sleep(200); //保证A先启动
new Thread(phone2::sendSMS, "B").start();
}
}
5.静态方法调用
package com.lh.juc;
import java.util.concurrent.TimeUnit;
class Phone {
public static synchronized void sendEmail() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("send email");
}
public static synchronized void sendSMS() {
System.out.println("send SMS");
}
public void hello() {
System.out.println("hello");
}
}
/**
* 5.两个静态同步方法,,先打印邮件还是短信 => 先打印邮件 => 静态同步方法 都属于类对象 所以是同一把锁 会造成竞争等待
*/
public class Lock8 {
public static void main(String[] args) throws Exception {
Phone phone = new Phone();
Phone phone2 = new Phone();
new Thread(Phone::sendEmail, "A").start();
Thread.sleep(200); //保证A先启动
new Thread(Phone::sendSMS, "B").start();
}
}
6.一个静态方法 一个普通方法
package com.lh.juc;
import java.util.concurrent.TimeUnit;
class Phone {
public static synchronized void sendEmail() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("send email");
}
public synchronized void sendSMS() {
System.out.println("send SMS");
}
public void hello() {
System.out.println("hello");
}
}
/**
* 8锁现象
* <p>
* 1.标准访问 先打印邮件还是短信 => 不一定啊 线程star后 由CPU来调用 =>先打印邮件
* 2.邮件方法暂停4秒 先打印邮件还是短信 => 邮件 => 同一个对象先执行的获取锁后来的的等待 synchronized 锁住的是当前资源类的对象
* 3.新增一个普通hello()方法 先打印邮件还是 hello() => 先打印hello => 普通方法不会竞争锁 直接执行
* 4.两个Phone对象 phone1 phone2 先打印邮件还是短信 =>先打印SMS => 两个不同的对象不是竞争的不是同一把锁 先进方法的先执行
* 5.两个静态同步方法,,先打印邮件还是短信 => 先打印邮件 => 静态同步方法 都属于类对象 所以是同一把锁 会造成竞争等待
* 6.一个静态同步方法 一个普通同步方法 => 先打印短信 => 静态的的锁资源属于类,普通方法的锁属于类的对象,不同的锁资源不需要竞争。
*/
public class Lock8 {
public static void main(String[] args) throws Exception {
Phone phone = new Phone();
Phone phone2 = new Phone();
new Thread(Phone::sendEmail, "A").start();
Thread.sleep(200); //保证A先启动
new Thread(phone::sendSMS, "B").start();
}
}
11.线程不安全集合类
异常:java.util.ConcurrentModificationException
1.List
1.导致原因
ArrayList 中的 add方法没有加上锁,多并发情况下上一个线程读数据时候下一个线程进行add操作会导致内存偏移抛出异常
2.解决方案:
1.Vector ()
2.Collections.syschronizedList(new ArrayList<>())
3.CopyOnWriteArrayList()
CopyOnWriteArrayList().add()方法源码
CopyOnWrite容器即是读写分离的容器。往一个容器中添加元素的时候,不直接在当前的Object[]中添加,而是将当前的Object[]Copy一份Object [] newElement, 然后往新容器中添加元素,添加完成之后通过 setArray(newElement)方法讲当前容器指向新的容器,这样做的好处是在并发的情况下发生读的操作时候不需要加上锁,因为当前容器不会添加任何元素。
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
12.JUC辅助类
1.CountDownLatch
配合 countDownLatch.countDown() 与 countDownLatch.await() 控制 执行顺序
package com.lh.juc.jucHelpClassDemo;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "离开工位");
countDownLatch.countDown();
}, String.valueOf(i)).start();
}
//阻塞 等待 countDown 减完为止
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"所有人都离开完毕 保安关门");
}
}
2.CyclicBarrier
package com.lh.juc.jucHelpClassDemo;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* 计数器 ++
*/
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(6, new Thread(() -> {
System.out.println("所有员工已经离开");
}));
for (int i = 1; i <= 6; i++) {
int i1 = i;
new Thread(() -> {
try {
System.out.println("第" + i1 + "员工离开工位");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}, String.valueOf(i)).start();
}
}
}
3.Semaphore
控制并发量
package com.lh.juc.jucHelpClassDemo;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* 控制多线程的并发数
*/
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3); //控制并发数为3 一共有三个位置
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
try {
semaphore.acquire(1); //线程进入后 剩余最大并发数-1 位置-1
System.out.println(Thread.currentThread().getName() + " 进入车位");
TimeUnit.SECONDS.sleep(3); //当前抢占到位置的等3秒
System.out.println(Thread.currentThread().getName() + " 离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release(); //释放当前位置
}
}, String.valueOf(i)).start();
}
}
}
4 .ReadWriteLock
多个线程不能同时进行写(读写、写写)的操作
- 写入没写完成的时候 这时候有个线程来读数据 (不满足数据一直性 即 读写不一致)以下代码会出现这个问题
package com.lh.juc.jucHelpClassDemo;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class MyCache {
private volatile Map<String, Object> map = new HashMap<>();
public void put(String key, String value) {
try {
System.out.println(Thread.currentThread().getName() + "开始写入");
TimeUnit.MILLISECONDS.sleep(300);
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "写入成功");
}catch (Exception e){}finally {
}
}
public void get(String key) {
try {
System.out.println(Thread.currentThread().getName() + "开始读取数据");
TimeUnit.MILLISECONDS.sleep(300);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName() + "读取数据成功:" + o);
}catch (Exception e){}finally {
}
}
}
public class ReadWriteLockDemo {
/**
* 模拟五个线程读 和五个五个线程写
*
* @param args
*/
public static void main(String[] args) {
MyCache myCache = new MyCache();
for (int i = 0; i < 6; i++) {
int i1 = i;
new Thread(() -> {
myCache.put(Thread.currentThread().getName(), String.valueOf(i1));
}, String.valueOf(i)).start();
}
for (int i = 0; i < 6; i++) {
int i1 = i;
new Thread(() -> {
myCache.get(Thread.currentThread().getName());
}, String.valueOf(i)).start();
}
}
}
- 使用ReadWriteLock后
package com.lh.juc.jucHelpClassDemo;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class MyCache {
private volatile Map<String, Object> map = new HashMap<>();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void put(String key, String value) {
try {
readWriteLock.writeLock().lock();
System.out.println(Thread.currentThread().getName() + "开始写入");
TimeUnit.MILLISECONDS.sleep(300);
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "写入成功");
}catch (Exception e){}finally {
readWriteLock.writeLock().unlock();
}
}
public void get(String key) {
try {
readWriteLock.readLock().lock();
System.out.println(Thread.currentThread().getName() + "开始读取数据");
TimeUnit.MILLISECONDS.sleep(300);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName() + "读取数据成功:" + o);
}catch (Exception e){}finally {
readWriteLock.readLock().unlock();
}
}
}
public class ReadWriteLockDemo {
/**
* 模拟五个线程读 和五个五个线程写
*
* @param args
*/
public static void main(String[] args) {
MyCache myCache = new MyCache();
for (int i = 0; i < 6; i++) {
int i1 = i;
new Thread(() -> {
myCache.put(Thread.currentThread().getName(), String.valueOf(i1));
}, String.valueOf(i)).start();
}
for (int i = 0; i < 6; i++) {
int i1 = i;
new Thread(() -> {
myCache.get(Thread.currentThread().getName());
}, String.valueOf(i)).start();
}
}
}
13.队列
1.阻塞队列
- 当队列是空的时候 从队列中获取数据被阻塞 NoSuchElementException
- 当队列是满的时候 往队列中添加数据被阻塞 Queue full
- 好处:不需要关系什么时候需要阻塞进程,使用阻塞队列就可以完成了
1.BlockingQueue(接口)
1.ArrayBlockingQueue 数组结构组成的有界阻塞队列
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
- add() 队列满了直接抛异常Queue full
- remove() 队列为空抛异常NoSuchElementException
- offer() 存入成功返回true,失败返回false
- offer (e,time,timeType)存入成功返回true,满了等待对应时间后还是不行返回失败false
- poll() 取出最新的元素 成功返回元素 ,没有返回null
- **poll(**time,timeType) 取出最新的元素 成功返回元素 ,没有返回等待时间之后还是不行返回null
- **put()**没有返回值,队列满了进入阻塞 等待
- **take()**没有返回值,队列空了进入阻塞 等待
2.LinkBlockingQueue 链表组成的有界阻塞队列
3.SynchronousQueue 单个元素的队列
14.线程池
1. 线程池的三大方法
(工作中一般不用 底层队列最大长度是Interger.maxValue很容易 挤压很多个线程 造成OOM)
1.FixedThreadPool 固定线程数线程池
2.newSingleThreadExecutor 一个线程数线程线程池
3.newCachedThreadPool 可伸缩线程数量线程池
package com.lh.juc;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyThreadPoolDemo {
public static void main(String[] args) {
ExecutorService fixThreadPool = Executors.newFixedThreadPool(5);
//ExecutorService fixThreadPool = Executors.newSingleThreadExecutor();
// ExecutorService fixThreadPool = Executors.newCachedThreadPool();
try {
for (int i = 0; i < 10; i++) {
//五个线程执行10个任务
fixThreadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + " 办理业务");
});
}
} catch (Exception e) {
} finally {
fixThreadPool.shutdown();
}
}
}
2.源码
//newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
//newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
//newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
1.七个主要参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
1.corePoolSize 线程池的核心线程数
2.maximumPoolSize 线程池中最大的线程数 (CPU 最大线程数+1)
System.out.println(Runtime.getRuntime().availableProcessors()); //查看电脑最大核数
3.keepAliveTime 多余空闲线程的存活时间,当线程池中的线程数超过corePoolSize时 超过了 keepAliveTime 多余的线程会被销毁
4.unit keepAliveTime的时间单位
5.wokeQueue 任务队列,被提交但是未被执行的任务
6.threadFactory 表示生成线程池中线程的线程工厂,一般用默认即可
7.handler:拒绝策略,表示当队列满了,并且工作的线程大于等于线程池的最大线程数时,如何来拒绝请求执行的runable策略
2.自定义线程池(重点!!)
package com.lh.juc;
import java.util.concurrent.*;
public class MyThreadPoolDemo {
public static void main(String[] args) {
ExecutorService threadPool = new ThreadPoolExecutor(
2,
Runtime.getRuntime().availableProcessors()+1, //系统最大核数+1
2L,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
//线程池最大容纳数量是 max+队列数
try {
for (int i = 0; i < 6; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + " 办理业务");
});
}
} catch (Exception e) {
} finally {
}
}
}
3.拒绝策略
1.AbortPolicy(默认) 直接抛出RejectedExcecutionException异常
2.CalleRunPolicy: 不会放弃任务也不会抛出异常,将某些任务回退给调用者
3.DiscardOldestPolicy 抛弃队列中等待最久的任务,然后把当前任务加入到队列中尝试再次提交当前任务
4.DisCardPolicy 丢弃无法处理的任务 且不会抛出异常
4.底层原理
步骤:
1.当创建线程池之后,开始等待请求。
2.当调用exectue()方法添加一个请求的任务时,线程池会做做出以下判断
- 如果正在运行的线程数量小于corePoolSize,马上就会创建线程来执行任务
- 如果正在运行的线程数量大于corePoolSize ,那么就会把线程方法队列中
- 如果队列已经满了且正在运行的线程数量还小于maxPoolSize,那么继续创建非核心线程来立即运行这个任务
- 如果队列满了且正在运行的线程数大于等于maxPoolSize那么线程池会启动拒绝策略来执行
3.当一个线程完成任务时,他就会从队列中取下一个任务来执行
4.当线程池中的某个线程超过keepAliveTime 时
- 如果当前线程池中的线程数量大于coolPoolSize ,那么这个线程就会被销毁
- 所以线程池中线程执行完所有的任务后,线程池的小最终会缩到coolPoolSize 的大小