JUC编程
1、java.util包
java不可以开启线程
java无法直接开启硬件
1.1进程、线程
进程:一个程序的集合,一个进程往往包含多个线程,至少包含一个线程
java默认有两个线程,main和GC(垃圾回收处理线程)
对于java而言,有三种方式开启线程Thread /Runable / Callable
1.2并发、并行
public static void main(String[] args) {
//获取CPU的核数,
//CPU密集型,IO密集型
System.out.println(Runtime.getRuntime().availableProcessors());
}
1.2.1并发
CPU只有一核,线程进行快速交替
1.2.2并行
CPU多核的情况下,可以同时执行,
线程池
1.2.3并发编程的实质
充分利用CPU的资源
2、多线程
2.1线程有几个状态
NEW 运行
RUNNABLE 运行
BLOCKED 阻塞
WAITING 等待,死死的等
TIME_WAITING 超时等待
TERMINATEO 终止等待
2.2wait与sleep的区别
-
来自不同的类
wait==>Object
Sleep==>Thread
-
关于锁的释放
wait会释放锁,sleep不会释放锁
-
使用范围不同
-
wait
只能在同步代码块中使用
-
sleep
可以在任意一个地方睡觉
-
-
是否需要捕获异常
- wait不需要捕获异常
- sleep需要捕获异常
3、lock锁
线程就是一个单独的资源类,没有任何的附属操作
真正的多线程的开发,公司中的开发,降低耦合度
并发操作同一个资源类,把资源类丢入线程
lambda表达式:
(参数)->{代码}
3.1、传统synchronized
本质就是锁,
是一个非公平锁
public class Test02 {
public static void main(String[] args) {
//并发,多个线程同时操作一个资源类,把资源类丢入线程池
Ticket ticket = new Ticket();
//lambda表达式
new Thread(()->{
for (int i = 50;i>0;i--){
ticket.sale();
}
},"A").start();
new Thread(()->{
for (int i = 50;i>0;i--){
ticket.sale();
}
},"B").start();
new Thread(()->{
for (int i = 50;i>0;i--){
ticket.sale();
}
},"C").start();
}
}
//资源类 OOP
class Ticket{
private Integer number = 50;
public synchronized void sale(){
if (number>0){
System.out.println(Thread.currentThread().getName()+"卖出"+(number--)+"号票"+"剩余:"+number);
}
}
}
3.2、Lock接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lNdMXu1B-1615246963772)(D:\File\学习文件\Typora文档\JAVA\JUC并发编程.assets\image-20210205143540347.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3MAMYG6R-1615246963782)(D:\File\学习文件\Typora文档\JAVA\JUC并发编程.assets\image-20210205143653096.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O32M2UxZ-1615246963783)(D:\File\学习文件\Typora文档\JAVA\JUC并发编程.assets\image-20210205151611115.png)]
公平锁:十分公平,可以先来后到
非公平锁:十分不公平:可以插队
默认使用的是非公平锁
3.3、Synchronized与Lock的区别
- synchronized 是java内置关键字,Lock是一个java类
- synchronized 无法判断获取锁的状态,Lock可以判断是否获取到了锁
- synchronized 可以自动的释放锁,Lock必须手动释放锁,不然就是
死锁
- synchronized 线程1(获得锁),线程2(傻傻的等待),Lock锁就不一定会等待下去
- synchronized 可以重入 锁,不可以中断,非公平锁;Lock可重入锁,可以判断锁,非公平(可以自己设置)
- synchronized 适合锁少量的代码同步问题,Lock适合锁大量的同步代码。
4、生产者和消费者的问题
4.1synchroized版本
public class Crement {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
try {
for (int i = 0;i<10;i++){
data.increment();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();
new Thread(()->{
try {
for (int i = 0; i < 10; i++) {
data.discrement();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
},"B").start();
}
}
/**
* 判断
* 业务
* 等待
* 唤醒
*/
class Data{
private Integer number = 0;
public synchronized void increment() throws InterruptedException {
if (number!=0){
//等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程,我执行完了
this.notifyAll();
}
public synchronized void discrement() throws InterruptedException {
if (number==0){
//等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"->"+number);
//通知其他线程,我执行完了
this.notifyAll();
}
}
4.1.1问题
如果存在多个线程,即A,B,C,D四个线程;会出现什么情况
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ut7paWk7-1615246963785)(D:\File\学习文件\Typora文档\JAVA\JUC并发编程.assets\image-20210205172502687.png)]
防止虚假唤醒
将if判断改为while判断
4.2新版本生产者消费者
实现步骤
1、创建锁
2、创建condition;Condition condition = lock.newCondition();
3、方法上锁
4、while(){condition.await()}
5、唤醒 condition.signal();
6、解锁lock.unlock();
固定模板:
Lock lock = new ReenTrantLock();
Connection connection = lock.newConnection();
lcok.lock();
try{
//业务代码块
while(true){
connection.await();
}
//业务
connection.signal();
}catch(Exception e){
}finally{
lock.unlock();
}
public class B {
public static void main(String[] args) {
Test02 data = new Test02();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
class Test02{
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void increment() throws InterruptedException {
lock.lock();
try {
while (number != 0){
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName()+"->"+number);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decrement() throws InterruptedException {
lock.lock();
try {
while (number==0){
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName()+"->"+number);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
4.3Condition实现精准唤醒
实现步骤
Lock lock = new ReentrantLock(); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition();
在进行各个唤醒
/**
* A执行完成调用B
* B执行完成调用C
* C执行完成调用A
*/
public class C {
public static void main(String[] args) {
Data3 data = new Data3();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printA();
}
},"AAA").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printB();
}
},"BBB").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printC();
}
},"CCC").start();
}
}
class Data3{
private int number = 1;
private Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
public void printA(){
lock.lock();
try {
while (number != 1){
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"->AAAAA");
number = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB(){
lock.lock();
try {
while (number != 2){
condition2.await();
}
System.out.println(Thread.currentThread().getName()+"->BBBB");
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try {
while (number != 3){
condition3.await();
}
System.out.println(Thread.currentThread().getName()+"->CCCC");
number = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
5、八锁现象
如何判断锁是谁,永远知道是什么锁,锁的到底是谁!!!
1、正常情况下,方法一、方法二(两个的顺序为方法一和方法二)两个方法都加上锁,而且使用的是同一把锁
-
当方法二和方法一之间间隔四秒在执行
是方法一先执行,执行完再去执行方法二;
-
方法一延迟两秒执行,
还是方法一先执行,再去执行方法二,两者的执行顺序不变;
2、方法一是加锁的,方法二为普通方法,两者之间间隔两秒执行
先执行方法二,再去执行方法一;synchronized锁的对象是方法的调用者,普通方法不是同步方法,不受锁的影响。
3、两个对象,两个同步方法
若方法一执行有四秒延迟,那么先执行方法二,两个方法互不干扰。
两个不同的对象,两把不同的锁;
4、两个方法都是静态的
static静态方法,是类一加载就有了,锁是class;
所以说两个静态方法还是使用的一个锁,只不过这两个方法不属于对象的了,是属于类的了;
5、两个静态方法,声明两个方法
因为static方法属于类的,锁是class,两个class类的模板只有一个
运行的时候,还是按照锁的先后顺序来的;
6、一个静态的同步方法,一个普通的同步方法
当只有一个对象的时候,先执行普通的同步方法,再执行静态同步方法;
当创建两个对象的时候,先执行普通的同步方法,在执行静态同步方法;因为一个属于对象的锁,一个属于类的锁,是两个不同的锁;
小结:
new this 具体的一个手机
static class 唯一的一个模板
6、集合类
1、CopyOnWriteArrayList
并发下ArrayList是不安全的
解决方案
-
解决方案一:
List list = new Vector<>();
-
解决方案二:
通过工具类转换为synchronized
List list = Collections.synchronizedList(new ArrayList<>());
-
解决方案三:
List list = new CopyOnWriteArrayList<>();
CopyOnWrite写入时复制,计算机程序设计领域的一种优化策略
多个线程调用的时候,List,读取的时候,固定的,写入(覆盖);
在写入的时候避免覆盖,造成数据问题,
CopyOnWriteArrayList比Vector好在哪里?
Vector线程是安全的,含有synchronized方法,会降低效率,
而CopyOnWriteArrayLis使用的是原生的javautil包,所以不会降低效率
2、CopyOnWriteArraySet
高并发下Set也是不安全的
解决方案
-
解决方法一:使用工具类转换为synchronized方法
Set set = Collections.synchronizedSet(new HashSet<>());
-
解决方法二:使用juc的CopyOnwriteArraySet()方法
Set set = new CopyOnWriteArraySet<>();
HashSet的底层就是HashMap
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Qch7Y31-1615246963787)(D:\File\学习文件\Typora文档\JAVA\JUC并发编程.assets\image-20210304210810921.png)]
3、ConcurrentHashMap
7、Callable
- 多线程的第三种创建方式
- 可以抛出异常
- 方法不同run()/call()
public class CallableTest {
public static void main(String[] args) {
Test test = new Test();
FutureTask futureTask = new FutureTask(test);//适配器
new Thread(futureTask,"A").start();
new Thread(futureTask,"B").start();//结果会被缓存,效率高
//获取返回值
try {
String o = (String) futureTask.get();//get方法可能会产生阻塞
// 或者通过异步通信来处理
System.out.println(o);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class Test implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("CAll()");
return "123456";
}
}
细节
Callable的结果会被缓存,如果多条线程执行,那么获取的只是原始的值;
get方法可能会产生阻塞
8、常用的辅助类
1、CountDownLatch
减数计算
允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。
A CountDownLatch
用给定的计数初始化。 await
方法阻塞,直到由于countDown()
方法的调用而导致当前计数达到零,之后所有等待线程被释放,并且任何后续的await
调用立即返回。 这是一个一次性的现象 - 计数无法重置。
public static void main(String[] args) throws InterruptedException {
CountDownLatch downLatch = new CountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"执行");
downLatch.countDown();//进行计数计算
},String.valueOf(i)).start();
}
downLatch.await();
System.out.println("执行完成");
}
downLatch.countDown();
计数
downLatch.await();
等待计数器归零,向下执行
每次调用线程CountDown()数量-1;假设计数器变为0,downLatch.await();
会被唤醒,继续向下执行
2、CyclicBarrier
加数计算
允许一组线程全部等待彼此达到共同屏障点的同步辅助。循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。屏障被称为循环 ,因为它可以在等待的线程被释放之后重新使用。
A CyclicBarrier
支持一个可选的Runnable
命令,每个屏障点运行一次,在派对中的最后一个线程到达之后,但在任何线程释放之前。 在任何一方继续进行之前,此屏障操作对更新共享状态很有用。
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5,()->{
System.out.println("达成五杀");
});
for (int i = 1; i <= 5; i++) {
final int temp = i;
new Thread(()->{
System.out.println("达成了"+temp+"杀");
try {
cyclicBarrier.await();//等待
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
3、Semaphore
信号量
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DoaDFwnO-1615246963788)(D:\File\学习文件\Typora文档\JAVA\JUC并发编程.assets\image-20210305105129690.png)]
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 10; i++) {
new Thread(()->{
try {
semaphore.acquire();//得到
System.out.println(Thread.currentThread().getName()+"抢到车位");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();//释放
}
},String.valueOf(i)).start();
}
}
原理
semaphore.acquire();
获得,假设如果已经满了,等待,等待被释放位置;
semaphore.release();
释放,当前的信号量会被增加1,然后唤醒等待的线程;
9、ReadWriteLock
读写锁
读的时候可以有多个线程同时去读,写的时候只能有一个线程去写
A ReadWriteLock
维护一对关联的locks
,一个用于只读操作,一个用于写入。 read lock
可以由多个阅读器线程同时进行,只要没有作者。 write lock
是独家的。
public class ReadWriteLockDemo {
public static void main(String[] args) {
Demo demo = new Demo();
for (int i = 1; i <= 6; i++) {
final int temp = i;
new Thread(()->{
demo.put(temp+"",temp);
},String.valueOf(i)).start();
}
for (int i = 1; i <= 6; i++) {
final int temp = i;
new Thread(()->{
demo.get(temp+"");
},String.valueOf(i)).start();
}
}
}
class Demo{
private volatile Map<String,Object> map = new HashMap<>();
//加入读写锁
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void put(String key,Object value){
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"写入"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入OK");
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
}
}
public void get(String key){
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"读取"+key);
map.get(key);
System.out.println(Thread.currentThread().getName()+"读取OK");
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
}
}
独占锁(写锁)
一次只能被一个线程占有
共享锁(读锁)
多个线程可以同时占有
ReadWriteLock
读-读 可以共存
读-写 不能共存
写-写 不能共存
10、阻塞队列
不得不阻塞
写入:如果队列满了,就必须阻塞等待
取:如果队列是空的,那么就必须等待生产
BlockingQueue
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2SZsiXu5-1615246963789)(D:\File\学习文件\Typora文档\JAVA\JUC并发编程.assets\image-20210306133918565.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KhbqPwMA-1615246963789)(D:\File\学习文件\Typora文档\JAVA\JUC并发编程.assets\image-20210306140209412.png)]
不是新的东西:什么情况下,我们会使用阻塞队列:多线程并发处理,线程池
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FL5ubOYN-1615246963790)(D:\File\学习文件\Typora文档\JAVA\JUC并发编程.assets\image-20210306140457384.png)]
什么情况下,我们会使用,阻塞队列,多线程并发处理,线程池;
**学会使用队列:**添加移除
四组API
- 抛出异常
- 不会抛出异常
- 阻塞、等待
- 超时等待
方式 | 抛出异常 | 有返回值,不抛出异常 | 阻塞,等待 | 超时等待 |
---|---|---|---|---|
添加 | add | offer() | put() | offer(参数,参数,参数) |
移除 | remove | poll() | take() | poll(参数,参数) |
检测队首元素 | element | peek | - | - |
抛出异常
public static void test1(){
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("b"));
System.out.println(blockingQueue.add("c"));
//抛出异常Queue full
//System.out.println(blockingQueue.add("d"));
//检测队首元素
System.out.println(blockingQueue.element());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
}
有返回值,不抛出异常
public static void test2(){
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
//添加元素
System.out.println(blockingQueue.offer("a"));
System.out.println(blockingQueue.offer("b"));
System.out.println(blockingQueue.offer("c"));
//如果超出队列最大值,那么就返回false
System.out.println(blockingQueue.offer("d"));
//检测队首队为元素
System.out.println(blockingQueue.peek());
//移除元素
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
}
阻塞,等待
public static void test3() throws InterruptedException {
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
//添加元素
blockingQueue.put("a");
blockingQueue.put("b");
blockingQueue.put("c");
//blockingQueue.put("d"); 队列没有,一直阻塞
blockingQueue.take();
blockingQueue.take();
blockingQueue.take();
//blockingQueue.take();没有元素,一直阻塞
}
超时等待
public static void test3() throws InterruptedException {
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
//添加元素
blockingQueue.offer("a");
blockingQueue.offer("b");
blockingQueue.offer("c");
blockingQueue.offer("d",2,TimeUnit.SECONDS);//等待超過两秒就退出
System.out.println("======================");
//移除元素
blockingQueue.poll();
blockingQueue.poll();
blockingQueue.poll();
blockingQueue.poll(2,TimeUnit.SECONDS);
}
同步队列
SynchronousQueue
public static void main(String[] args) {
BlockingQueue<String> blockingQueue = new SynchronousQueue<>(); //同步队列
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName()+"put a");
blockingQueue.put("a");
System.out.println(Thread.currentThread().getName()+"put b");
blockingQueue.put("b");
System.out.println(Thread.currentThread().getName()+"put c");
blockingQueue.put("c");
} catch (InterruptedException e) {
e.printStackTrace();
}
},"T1").start();
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"=>"+blockingQueue.take());
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"=>"+blockingQueue.take());
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"=>"+blockingQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
},"T2").start();
}
11、线程池
池化技术
程序运行本质:占用系统资源!优化资源的使用!=>池化技术
线程池,连接池,内存池,对象池, //创建…销毁,十分的浪费资源
池化技术:事先准备好一些资源,有人要用,那么就从我这里来拿,用完在还给我;
线程池的好处
1、降低资源点的损耗
2、提高相应速度
3、方便管理
线程池的复用,可以控制最大并发数、管理线程
1)、线程池三大方法
Executors.newSingleThreadExecutor(); 创建单一个一个线程池
Executors.newFixedThreadPool(5); 创建固定数量的线程
Executors.newCachedThreadPool(); 根据线程的数量来变化线程池中线程的数量;弹性变化
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();//创建单一个一个线程池
//ExecutorService threadPool = Executors.newFixedThreadPool(5);//创建固定的线程的数量
//ExecutorService threadPool = Executors.newCachedThreadPool();//根据线程的数量来变化线程池中线程的数量;弹性变化
//通过线程池创建线程
try {
for (int i = 0; i < 100; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName());
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//线程池用完,程序结束,关闭线程池
threadPool.shutdown();
}
}
2)、七大参数
自定义线程池
//自定义线程池
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
new ThreadPoolExecutor.DiscardOldestPolicy());
源码分析
参数 | 说明 |
---|---|
int corePoolSize | 核心线程池大小 |
int maximumPoolSize | 最大线程池大小 |
long keepAliveTime | 超时时间,用就释放 |
TimeUnit unit | 超时单位 |
BlockingQueue workQueue | 阻塞队列 |
ThreadFactory threadFactory | 线程池工厂,一般不用动 |
RejectedExecutionHandler handler | 拒绝策略(一共四种) |
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,//约等于21亿
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
//本质都是调用的:ThreadPoolExecutor
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;
}
int corePoolSize, //核心线程池大小
int maximumPoolSize, //最大线程池大小
long keepAliveTime, //超时了,没有人用就会被释放
TimeUnit unit, //超时单位
BlockingQueue<Runnable> workQueue, //阻塞队列
ThreadFactory threadFactory, //线程池工厂,创建线程池用的,一般不用动
RejectedExecutionHandler handler //拒绝策略
3)、四种拒绝策略
决绝策略 | 说明 |
---|---|
new ThreadPoolExecutor.AbortPolicy | 队列满了,不处理,直接抛出异常 |
new ThreadPoolExecutor.CallerRunsPolicy | 从哪里来的回哪里去 |
new ThreadPoolExecutor.DiscardOldestPolicy | 队列满了,丢掉任务,不抛出异常 |
new ThreadPoolExecutor.DiscardPolicy | 队列满了,尝试和最早的竞争,也不会抛出异常 |
4)、小结和拓展
最大线程到底该如何定义
IO密集型。CPU密集型;(调优)
-
CPU 密集型,几核就是几核,可以保持CPU效率最高
-
IO 密集型 > 判断你程序中身份耗CPU中最耗IO的线程
-
程序 15个大型任务, IO十分占用资源;
-
获取CPU的核数
Runtime.getRuntime().availableProcessors();
12、四大函数式接口
1)、四大原生的函数式接口
简化编程模型
Consumer
Function
Predicate
Supplier
2)、Function
函数型接口
public static void main(String[] args) {
//工具类,输出输入的类
//有一个输入参数,有一个输出参数,函数接口型可以使用lambda表达式
/* Function function = new Function<String,String>() {
@Override
public String apply(String str) {
return str;
}
};*/
//使用lambda进行简化
Function<String,String> function = (str)->{return str;};
System.out.println(function.apply("abc"));
}
3)、Predicate
段定型接口,只有一个输入参数,返回值只能是布尔值
public static void main(String[] args) {
/*Predicate<String> predicate = new Predicate<String>() {
@Override
public boolean test(String str) {
return str.isEmpty();
}
};*/
Predicate<String> predicate = str->{return str.isEmpty();};
System.out.println(predicate.test("aa"));
}
4)、Consumer
消费型接口,只有输入参数值,没有返回值
public static void main(String[] args) {
/*Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String str) {
System.out.println(str);
}
};*/
Consumer<String> consumer = str->{
System.out.println(str);
};
consumer.accept("这只是一个消费性的接口");
}
5)、Supplier
供给型接口,没有参数,只有返回值
public static void main(String[] args) {
/*Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return "供给型函数式接口";
}
};*/
Supplier<String> supplier = ()->{return "供给型函数式接口";};
System.out.println(supplier.get());
}
13、Stream流式计算
计算都应该交给流来计算
/**
* 一分钟完成此题,只用一行代码实现
* 现在有5个用户,筛选
* 1、id必须是偶数
* 2、年龄必须大于23岁
* 3、用户名转换为大写
* 4、用户名倒着排序
* 5、只输出一个用户名
*/
public class SteamDemo {
public static void main(String[] args) {
User u1 = new User(1,"a",21);
User u2 = new User(2,"b",22);
User u3 = new User(3,"c",23);
User u4 = new User(4,"d",24);
User u5 = new User(5,"e",25);
User u6 = new User(6,"f",26);
List<User> users = Arrays.asList(u1,u2,u3,u4,u5,u6);
//集合就是存储数据,计算交给stream流
//连式编程
users.stream()
.filter(user -> {return user.getId()%2==0;})
.filter(user -> {return user.getAge()>23;})
.map(user->{return user.getName().toUpperCase();})
.sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
.limit(1)
.forEach(System.out::println);
}
}
14、ForkJoin
什么是ForkJoin
并行执行任务,提高效率;就是把大任务拆分成小任务,然后在把小任务结果进行整合;
工作窃取
这里面维护的都是双端队列
turn “供给型函数式接口”;
}
};*/
Supplier supplier = ()->{return “供给型函数式接口”;};
System.out.println(supplier.get());
}
## 13、Stream流式计算
计算都应该交给流来计算
```java
/**
* 一分钟完成此题,只用一行代码实现
* 现在有5个用户,筛选
* 1、id必须是偶数
* 2、年龄必须大于23岁
* 3、用户名转换为大写
* 4、用户名倒着排序
* 5、只输出一个用户名
*/
public class SteamDemo {
public static void main(String[] args) {
User u1 = new User(1,"a",21);
User u2 = new User(2,"b",22);
User u3 = new User(3,"c",23);
User u4 = new User(4,"d",24);
User u5 = new User(5,"e",25);
User u6 = new User(6,"f",26);
List<User> users = Arrays.asList(u1,u2,u3,u4,u5,u6);
//集合就是存储数据,计算交给stream流
//连式编程
users.stream()
.filter(user -> {return user.getId()%2==0;})
.filter(user -> {return user.getAge()>23;})
.map(user->{return user.getName().toUpperCase();})
.sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
.limit(1)
.forEach(System.out::println);
}
}
14、ForkJoin
什么是ForkJoin
并行执行任务,提高效率;就是把大任务拆分成小任务,然后在把小任务结果进行整合;
工作窃取
这里面维护的都是双端队列
两个线程A、B同时执行,当线程B执行完成了,而线程A还未执行完成,那么线程B就会把线程A的任务给拿过来,从而提高线程效率;