COW 的思想:(不要害怕看源码,因为到了最底层都是你能够看懂的代码)
多看阿里巴巴开发手册!
1、所有的知识,你能吸收多少,更多取决于自己,自律性!
2、老师讲的所有的知识,就好比一座山,能搬走多少看自己的努力
3、下去要多巩固,多看,多问!
4、对自己的学习结果负责
架构:高内聚,低耦合
1 先有一个资源类
2 然后多线程操纵资源类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gHaANxwt-1583501035630)(C:\Users\quinc\AppData\Roaming\Typora\typora-user-images\image-20200301225414992.png)]
线程之间通信:判断、执行、通知
(JUC版sleep: 用TimeUnit类,例如TimeUnit.SECONDS.sleep(2)):
wait | sleep | |
---|---|---|
调用者 | Object对象 | Thread类静态调用 |
释放锁 | Y | N |
使用范围 | 与notify成组使用、用于线程通信 | 单独使用、哪里都可以用 |
异常捕获 | 可以不捕获 | 需捕获 |
synchronized | java.util.concurrent.locks.Lock | |
---|---|---|
语法 | 关键字 | 接口 |
尝试获取锁 | N、若A获得则B一直等待 | Y、可尝试获取若失败则放弃 |
自动释放锁 | Y | N |
公平锁 | N | 默认非公平、可设置 |
精准控制 | N、适合代码量小的同步 | Y |
独占锁(写锁):一次只能被一个线程占有
共享锁(读锁):该锁可以被多个线程占有
不安全集合类 | 安全集合类 |
---|---|
ArrayList | CopyOnWriteArrayList |
HashSet | CopyOnWriteArraySet |
HashMap | ConcurrentHashMap |
方法 | 第一组会抛出异常 | 返回一个布尔值,不会抛出异常 | 延时等待 | 一直等待(阻塞) |
---|---|---|---|---|
插入 | add() | offer(e) | offer(e,time) | put() |
取出 | remove() | poll() | poll(time) | take() |
检查 | element() | peek() | - | - |
虚假唤醒->用while代替if
https://www.cnblogs.com/set-cookie/p/8728907.html
线程之间的通信design pattern: 判断 执行 通知
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6NZhbOhz-1583501035632)(C:\Users\quinc\AppData\Roaming\Typora\typora-user-images\image-20200306214259538.png)]
copyonwriteLIST
CopyonWriteSet
concurrentHashmap
ReentrantReadWriteLock
牢记基本原理:被 synchronized 修饰的方式,锁的对象是方法的调用者。如果是放在函数级别的syncronized修饰符,那么是class级别的。
小结
1、new this 调用的这个对象,是一个具体的对象!
2、static class 唯一的一个模板!
synchronized | JUC版 | |
---|---|---|
判断条件 | Object | Condition |
等待方法 | wait | await |
通知方法 | notify/notifyAll | signal/signalAll |
不安全集合类 | 安全集合类 |
---|---|
ArrayList | CopyOnWriteArrayList |
HashSet | CopyOnWriteArraySet |
HashMap | ConcurrentHashMap |
方法 | 第一组会抛出异常 | 返回一个布尔值,不会抛出异常 | 延时等待 | 一直等待(阻塞) |
---|---|---|---|---|
插入 | add() | offer(e) | offer(e,time) | put() |
取出 | remove() | poll() | poll(time) | take() |
检查 | element() | peek() | - | - |
ReentrantReadWriteLock https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-apExY4pM-1583501035633)(C:\Users\quinc\AppData\Roaming\Typora\typora-user-images\image-20200306220529969.png)]
插入 | add() | offer(e) | offer(e,time) | put() |
---|---|---|---|---|
取出 | remove() | poll() | poll(time) | take() |
方法 | 第一组会抛出异常 | 返回一个布尔值,不会抛出异常 | 延时等待 | 一直等待 |
检查 | element() | peek() | - | - |
彩蛋:同步队列
SynchronousQueue , 只有一个容量!
每一个put操作,就需要有一个 take操作!
为什么要用线程池?线程复用。(不用回答太多废话)
为什么阿里不允许使用executors 去创建线程池?
《阿里巴巴开发规范手册》提醒:这种创建线程池的方式忌用,因为 容易引起 OOM。源码中,Integer.MAX_VALUE 最大达到 21亿4千7百万,一般电脑是不可能做到,危害性不言而喻。
3大方法
ExecutorService threadPool = Executors.newSingleThreadExecutor();
固定的线程数
ExecutorService threadPool = Executors.newFixedThreadPool(8);
// 遇强则强!可伸缩!
ExecutorService threadPool = Executors.newCachedThreadPool();
7大参数
public ThreadPoolExecutor(int corePoolSize, // 核心池线程数大小 (常用)
int maximumPoolSize, // 最大的线程数大小 (常用)
long keepAliveTime, // 超时等待时间 (常用)
TimeUnit unit, // 时间单位 (常用)
BlockingQueue workQueue, // 阻塞队列(常用)
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略(常用)) {
4种拒绝策略:
* 1、ThreadPoolExecutor.AbortPolicy(); 抛出异常,丢弃任务
* 思路:看到效果一样的东西,可以研究研究!
* 2、ThreadPoolExecutor.DiscardPolicy();不抛出异常,丢弃任务
* 3、ThreadPoolExecutor.DiscardOldestPolicy(); 尝试获取任务,不一定执行!
* 4、ThreadPoolExecutor.CallerRunsPolicy(); 哪来的去哪里找对应的线程执行!
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
new ThreadPoolExecutor.DiscardPolicy());
CPU密集型(计算密集型) | 最大线程数=CPU核数=Runtime.getRuntime().availableProcessors(); 推荐使用Stream接口 |
IO密集型: | 最大线程数=IO任务的倍数、不能低于IO任务的数量;使用CompletableFuture灵活性更好 |
总结一下:io操作多的的线程个数公式跟CPU密集型的不一样。最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目
所有的函数式接口,函数式接口是我们现在必须要掌握且精通的
Function | 传入一个参数, | 输出一个参数 |
---|---|---|
cousumer(消费者) | 传入一个参数 | 不输出参数 |
supplier(生产者) | 没有输入参数 | 只有输出参数 |
predicate | 传入一个参数 | 返回判断值(Boolean) |
大数据时代重点: 存储和计算
1.5 枚举,反射,注解,泛型
1.8 functional, stream,lamda,链式编程
上文中已经提到了在Java 8引入了自动并行化的概念。它能够让一部分Java代码自动地以并行的方式执行,也就是我们使用了ForkJoinPool的ParallelStream。
Java 8为ForkJoinPool添加了一个通用线程池,这个线程池用来处理那些没有被显式提交到任何线程池的任务。它是ForkJoinPool类型上的一个静态元素,它拥有的默认线程数量等于运行计算机上的处理器数量。当调用Arrays类上添加的新方法时,自动并行化就会发生。比如用来排序一个数组的并行快速排序,用来对一个数组中的元素进行并行遍历。自动并行化也被运用在Java 8新添加的Stream API中。
package com.coding.future;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class CompletableFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 没有返回值,好比多线程,功能更强大!
// CompletableFuture completableFuture = CompletableFuture.runAsync(() -> {
// try {
// TimeUnit.SECONDS.sleep(2);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName() + “没有返回值!”);
// });
// System.out.println(“111111”);
// completableFuture.get();
// 有返回值
// 任务
CompletableFuture uCompletableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName()+"=>supplyAsync!");
int i = 10/0;
return 1024;
});
System.out.println(uCompletableFuture.whenComplete((t, u) -> { // 成功
System.out.println("t=>" + t); // 正确结果
System.out.println("u=>" + u); // 错误信息
}).exceptionally(e -> { // 失败,如果错误就返回错误的结果!
System.out.println("e:" + e.getMessage());
return 500;
}).get());
}
}
什么是 forkjoin
MapReduce:input->split->map->reduce->output
主要就是两步:
1、任务拆分
2、结果合并
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QGKSz1wB-1583501035634)(E:/WorkingDocument/2020艾编程相关/3.4号 JUC(中)/Juc并发编程课堂笔记.assets/image-20200304223011997.png)]
前提:forkjoin 一定是用在大数据量的情况下
工作原理:工作窃取
底层维护的是一个双端队列;
好处:效率高
坏处:产生资源争夺
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DV5S1BpT-1583501035634)(E:/WorkingDocument/2020艾编程相关/3.4号 JUC(中)/Juc并发编程课堂笔记.assets/image-20200304223252511.png)]
测试一下Forkjoin
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hoERi3ZI-1583501035635)(E:/WorkingDocument/2020艾编程相关/3.4号 JUC(中)/Juc并发编程课堂笔记.assets/image-20200304223538382.png)]
Future
CompletableFuture
代码测试
package com.coding.future;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class CompletableFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 没有返回值,好比多线程,功能更强大!
// CompletableFuture completableFuture = CompletableFuture.runAsync(() -> {
// try {
// TimeUnit.SECONDS.sleep(2);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName() + "没有返回值!");
// });
// System.out.println("111111");
// completableFuture.get();
// 有返回值
// 任务
CompletableFuture<Integer> uCompletableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName()+"=>supplyAsync!");
int i = 10/0;
return 1024;
});
System.out.println(uCompletableFuture.whenComplete((t, u) -> { // 成功
System.out.println("t=>" + t); // 正确结果
System.out.println("u=>" + u); // 错误信息
}).exceptionally(e -> { // 失败,如果错误就返回错误的结果!
System.out.println("e:" + e.getMessage());
return 500;
}).get());
}
}
Volatile 保证原子操作(包括long&double,还有基本类型)跟禁止指令重排。ThreadLocal模板类是某一个线程里面保存一个副本,但是值的有效性是要程序自己更新的.
主存会自动修改线程的副本 | 支持类型 | |
---|---|---|
Volatile | Y | 基本类型,引用类型只能保证引用的更新。 |
ThreadLocal | N | 模板类,支持存储各种class |
https://www.zhihu.com/question/31990408
https://blog.csdn.net/qq_31489805/article/details/78456048
https://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html
https://www.ibm.com/developerworks/java/library/j-jtp06197/
· guarantees atomic writes to double/long
· guarantees that when a thread A sees change in volatile variable made by thread B, thread A can also see all other changes made by thread B before the change to volatile variable (think setting the number of used cells in array after setting the cells themselves).
· prevents compiler optimization based on assumption that only one thread can change the variable (think tight loop while (l != 0) {}.
ThreadLocal
instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ThreadLocal.html
Class ThreadLocal
Example:
public class ThreadLocalExample {
public static void main(String[] args) {
MyRunnable sharedRunnableInstance = new MyRunnable();
Thread thread1 = new Thread(sharedRunnableInstance);
Thread thread2 = new Thread(sharedRunnableInstance);
thread1.start();
thread2.start();
thread1.join(); //wait for thread 1 to terminate
thread2.join(); //wait for thread 2 to terminate
}
}
public class MyRunnable implements Runnable {
private ThreadLocal threadLocal = new ThreadLocal();
@Override
public void run() {
threadLocal.set( (int) (Math.random() * 100D) );
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println(threadLocal.get());
}
}
原因是因为?