JUC
JUC是Java.util.concurrent下面的一个工具包
线程和进程的概念
进程与线程
进程:指系统中正在运行的一个应用程序;程序一旦运行就是进程;进程是资源分配的最小单位
线程:系统分配处理器时间资源的基本单位,或者说进程之类独立执行的一个单元执行流。线程是程序执行的最小单位
线程的状态
NEW(新建)
RUNNABLE(准备就绪)
BLOCKED(阻塞)
WAITING(不见不散)
TIMED_WAITING(过时不候)
TERMINATED(终结)
wait和sleep的区别
(1)、sleep是Thread的静态方法,wait是Object的方法,任何对象实例都能调用
(2)、sleep不会释放锁,它也不需要占用锁,wait会释放锁,但调用它的前提是当前线程占有锁(即代码要在synchronized中)
(3)、它们都可以被interrupted方法中断
并发和并行
并发:同一时刻多个线程在访问同一资源,多个线程对一个点
并行:多项工作一起执行,之后再汇总
管程(Monitor)
是一种同步机制,保证同一个时间,只有一个线程能访问被保护的数据或者代码。JVM同步是基于进入和退出进行操作的,就是使用的管程对象实现的
用户线程和守护线程
用户线程:自定义线程
守护线程:在后台默默执行的(垃圾回收)
public class Test {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "--是否守护线程:" + Thread.currentThread().isDaemon());
while (true) {
}
}, "线程1");
//设置守护线程
thread.setDaemon(true);
thread.start();
System.out.println(Thread.currentThread().getName() + "over");
}
}
总结:如果是用户线程,主线程结束了,用户线程还在运行,jvm存活。如果没有用户线程了,都是守护线程,jvm结束。
Lock接口
synchronized关键字
synchronized是Java中的关键字,是一种同步锁
- 修饰的对象
- 代码块,被修饰的代码块称为同步语句块,作用范围是大括号{}的代码,作用的对象是调用这个代码块的对象
- 方法,被修饰的方法称为同步方法,作用范围整个方法,作用的对象是调用这个方法的对象
- 静态方法,作用范围整个静态方法,作用对象是这个类的所有对象
- 修饰一个类,作用范围是synchronized后面括起来的部分,作用对象是这个类的所有对象
synchronized锁实现卖票
//1.创建资源类,定义属性和方法
class Ticket {
//票数
private int number = 30;
//操作方法:卖票
public synchronized void sale() {
//判断:是否有票
if (number > 0) {
number--;
System.out.println(Thread.currentThread().getName() + "剩下票数:" + (number));
}
}
}
public class SaleTicket {
public static void main(String[] args) {
Ticket ticket = new Ticket();
//创建三个线程
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}
}, "AA").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}
}, "BB").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}
}, "CC").start();
}
}
ReentrantLock可重入锁实现卖票
class LTicket {
//创建可重入锁
private final ReentrantLock lock = new ReentrantLock();
private int number = 30;
public void sale() {
//上锁
lock.lock();
try {
if (number > 0) {
number--;
System.out.println(Thread.currentThread().getName() + "剩下票数:" + (number));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//解锁
lock.unlock();
}
}
}
public class LSaleTicket {
public static void main(String[] args) {
LTicket lTicket = new LTicket();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
lTicket.sale();
}
}, "AA").start();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
lTicket.sale();
}
}, "BB").start();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
lTicket.sale();
}
}, "CC").start();
}
}
Lock和synchronized区别
- Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的Java语言实现
- synchronized在发生异常的时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unlock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在Finally块中释放锁
- Lock可以让等待的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断
- 通过Lock可以知道有没有成功释放锁,而synchronized却无法办到。
- Lock可以提高多个线程进行读操作的效率
线程间的通信
- 多线程的编程步骤
- 创建资源类,创建属性和操作方法
- 在资源类操作方法(1)判断、(2)干活、(3)通知
- 创建多线程调用资源类的方法
- 防止虚假唤醒问题(在while中进行判断)
synchronized实现线程通信(交替执行)
class Share {
//初始值
private int num = 0;
//+1的方法
public synchronized void incr() throws InterruptedException {
//第二步 判断 干活 通知
//判断num是否是0,如果不是,等待
if (num != 0) {
this.wait();
}
//如果num是0,就+1操作
num++;
System.out.println(Thread.currentThread().getName() + "::" + num);
//通知其他线程
this.notifyAll();
}
//-1的方法
public synchronized void decr() throws InterruptedException {
//判断
if (num != 1) {
this.wait();
}
//干活
num--;
System.out.println(Thread.currentThread().getName() + "::" + num);
//通知
this.notifyAll();
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
//第三步 创建多线程 调用资源类的操作方法
Share share = new Share();
//创建线程
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
share.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "AA").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
share.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "BB").start();
}
}
问题: 如果不止两个线程,再次新增两个线程实现递增和递减,会出现线程虚假唤醒问题;因为wait()方法在哪里睡就会在哪里醒
解决: if判断需要修改成while判断
Lock实现线程通信(交替执行)
class Share {
//初始值
private int num = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
//+1的方法
public void incr() throws InterruptedException {
//第二步 判断 干活 通知
//判断num是否是0,如果不是,等待
lock.lock();
try {
while (num != 0) {
condition.await();
}
//如果num是0,就+1操作
num++;
System.out.println(Thread.currentThread().getName() + "::" + num);
//通知其他线程
condition.signalAll();
} finally {
lock.unlock();
}
}
//-1的方法
public void decr() throws InterruptedException {
lock.lock();
try {
while (num != 1) {
condition.await();
}
//如果num是0,就+1操作
num--;
System.out.println(Thread.currentThread().getName() + "::" + num);
//通知其他线程
condition.signalAll();
} finally {
lock.unlock();
}
}
}
public class ThreadDemo2 {
public static void main(String[] args) {
//第三步 创建多线程 调用资源类的操作方法
Share share = new Share();
//创建线程
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
share.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "AA").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
share.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "BB").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
share.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "CC").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
share.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "DD").start();
}
}
线程间定制化通信
//第一步 创建资源类
class ShareResource {
//定义标志位
private int flag = 1;
//创建Lock锁
private Lock lock = new ReentrantLock();
//创建三个Condition
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
//打印5次
public void print5(int loop) {
lock.lock();
try {
while (flag != 1) {
condition1.await();
}
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + "值:" + i + "循环轮数" + loop);
}
flag = 2;
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void print10(int loop) {
lock.lock();
try {
while (flag != 2) {
condition2.await();
}
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + "值:" + i + "循环轮数" + loop);
}
flag = 3;
condition3.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void print15(int loop) {
lock.lock();
try {
while (flag != 3) {
condition3.await();
}
for (int i = 1; i <= 15; i++) {
System.out.println(Thread.currentThread().getName() + "值:" + i + "循环轮数" + loop);
}
flag = 1;
condition1.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class ThreadDemo3 {
public static void main(String[] args) {
ShareResource shareResource = new ShareResource();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
shareResource.print5(i);
}
}, "AA").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
shareResource.print10(i);
}
}, "BB").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
shareResource.print15(i);
}
}, "CC").start();
}
}
集合的线程安全
ArrayList
public class ListDemo {
public static void main(String[] args) {
/**
* 线程不安全,
* 故障现象:java.util.ConcurrentModificationException
* 导致原因:类似签到->A员工签到,签到一半B员工去抢夺签到,就会导致并发修改异常
* 一个人正在写入,另外一个人过来抢夺,导致数据不一致异常
* 解决:
* 1.new Vector<>();
* 2.Collections.synchronizedList(new ArrayList<>());
* 3.new CopyOnWriteArrayList();
* new CopyOnWriteArrayList() 底层实现:写时复制、读写分离的思想
* 往一个容器添加元素的时候,不直接往当前容器Object[]添加,而是先将当前容器复制一份
* ,然后对新的容器里面添加元素,添加完元素后,再将原容器的引用地址指向新的容器。这样做的
* 好处是可以对容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素,所以这也是一种
* 读写分离的好思想,读和写不同的容器
* 优化建议:
*/
List<String> list = new ArrayList<>();
for (int i = 0; i < 50; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
}
HashSet
public class SetDemo {
public static void main(String[] args) {
/**
* 线程不安全,
* 故障现象:java.util.ConcurrentModificationException
* 解决:
* 1.Collections.synchronizedSet(new HashSet<>());
* 2.new CopyOnWriteArraySet();
*/
Set<String> set = new HashSet<>();
for (int i = 0; i < 50; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(set);
}, String.valueOf(i)).start();
}
}
}
HashMap
public class MapDemo {
public static void main(String[] args) {
/**
* 线程不安全,
* 故障现象:java.util.ConcurrentModificationException
* 解决:
* 1.new ConcurrentHashMap();
*/
Map<String, String> map = new HashMap<>();
for (int i = 0; i < 50; i++) {
String key = String.valueOf(i);
new Thread(() -> {
map.put(key, UUID.randomUUID().toString().substring(0, 8));
System.out.println(map);
}, String.valueOf(i)).start();
}
}
}
多线程锁
synchronized实现同步的基础:Java中的每一个对象都可以作为锁
具体表现为以下三种形式:
- 对于普通同步方法,锁的是当前实例对象
- 对于静态同步方法,锁的是当前类的Class对象
- 对于同步方法块,锁的是synchronized括号里配置的对象
公平锁和非公平锁
非公平锁(默认):效率高,但是会出现线程饿死情况
Lock lock = new ReentrantLock();
Lock lock = new ReentrantLock(false);
公平锁:效率相对低,不会出现线程饿死情况
Lock lock = new ReentrantLock(true);
可重入锁
synchronized(隐式)和Lock(显式)都是可重入锁
synchronized实现可重入锁
public class Test {
public static void main(String[] args) throws InterruptedException {
Object o = new Object();
synchronized (o) {
System.out.println("外层");
synchronized (o) {
System.out.println("中层");
synchronized (o) {
System.out.println("内层");
}
}
}
}
}
Lock实现可重入锁
public class Test {
public static void main(String[] args) throws InterruptedException {
Lock lock = new ReentrantLock();
lock.lock();
try {
System.out.println("外层");
lock.lock();
try {
System.out.println("中层");
lock.lock();
try {
System.out.println("内层");
} finally {
lock.unlock();
}
} finally {
lock.unlock();
}
} finally {
lock.unlock();
}
}
}
死锁
两个或者两个以上进程在执行过程中,因为争夺资源而造成一种互相等待的现象,如果没有外力干涉,他们无法再继续执行下去
代码实现
public class Test {
static Object a = new Object();
static Object b = new Object();
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
synchronized (a) {
System.out.println(Thread.currentThread().getName() + "持有锁a,试图获取锁b");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {
System.out.println(Thread.currentThread().getName() + "获取锁b");
}
}
}, "AA").start();
new Thread(() -> {
synchronized (b) {
System.out.println(Thread.currentThread().getName() + "持有锁b,试图获取锁a");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a) {
System.out.println(Thread.currentThread().getName() + "获取锁a");
}
}
}, "BB").start();
}
}
Java多线程
多线程创建的几种方式
- 继承Thread
public class Test {
public static void main(String[] args) {
System.out.println("main方法...start");
Thread thread = new Thread01();
thread.start();
System.out.println("main方法...end");
}
public static class Thread01 extends Thread {
@Override
public void run() {
System.out.println("当前线程---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果---" + num);
}
}
}
- 实现Runnable接口
public class Test {
public static void main(String[] args) {
System.out.println("main方法...start");
Runnable01 runnable01 = new Runnable01();
Thread thread = new Thread(runnable01);
thread.start();
System.out.println("main方法...end");
}
public static class Runnable01 implements Runnable {
@Override
public void run() {
System.out.println("当前线程---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果---" + num);
}
}
}
- 实现Callable接口+FutureTask(可以拿到返回结果,可以处理异常)
public class Test {
public static void main(String[] args) {
System.out.println("main方法...start");
FutureTask<Object> futureTask = new FutureTask<>(new Callable01());
Thread thread = new Thread(futureTask);
thread.start();
Object o = null;
try {
//阻塞等待 等待整个线程执行完成,获取返回结果
o = futureTask.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//需要等待获取到返回结果才会进行打印
System.out.println("main方法...end==>" + o);
}
/**
* Callable<Object> ==>Object对应需要返回的结果
*/
public static class Callable01 implements Callable<Object> {
@Override
public Object call() throws Exception {
System.out.println("当前线程---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果---" + num);
return num;
}
}
}
- 线程池(推荐使用) 以上三种方式创建线程不推荐使用,如果多个请求每次new Thread();可能会导致我们资源耗尽;我们应该将所有的异步线程任务交给线程池执行
/**
* 根据Executors来创建线程池
*/
public class Test {
/**
* 当前系统中池的数量应该只会有一两个(根据自己的业务场景来定);每个异步任务,提交给线程池让它自己去执行
* Executors.newFixedThreadPool(10) 获取一个定长线程池
*/
public static ExecutorService executor = Executors.newFixedThreadPool(10);
/**
* 七个参数
* int corePoolSize :核心线程数【一直存在,除非设置allowCoreThreadTimeOut】,线程池创建好之后就准备就绪的线程数量,就等待来接收异步线程任务去执行
* int maximumPoolSize :最大线程数;控制资源(CPU密集型[CPU核数+1]、IO密集型[CPU核数*2、CPU核数/(1-阻塞系数[0.8~0.9])])
* long keepAliveTime : 存活时间(如果当前线程数量大于核心数量,释放空闲线程[maximumPoolSize-corePoolSize]需要的时间)
* TimeUnit unit : 时间单位
* BlockingQueue<Runnable> workQueue : 阻塞队列。如果任务有很多,就会将目前对的任务放在队列,只要有线程空闲了,就会从队列中取出新的任务继续执行
* ThreadFactory threadFactory : 线程创建工厂
* RejectedExecutionHandler handler : 如果队列满了,按照我们指定的拒绝策略拒绝执行任务(new AbortPolicy()[默认,直接抛出异常阻止系统正常运行]、new DiscardPolicy()[直接丢弃进来的任务]、new DiscardOldestPolicy()[丢弃等待最久的任务]、new CallerRunsPolicy()[不抛弃任务,也不丢弃任务,将任务回退给调用者])
* <p>
* 执行顺序:
* 1.线程池创建好,准备core数量的核心线程,准备接收任务
* 2.如果核心线程数满了,再进来的任务就放入阻塞队列,空闲的线程就自己会去阻塞队列里面获取任务执行
* 3.阻塞队列如果也满了,就会直接开新线程执行,最大开到max指定的数量
* 4.如果max满了,就会使用拒绝策略拒绝任务
* 5.max没满都执行完了,有很多空闲线程;就会在指定的时间(keepAliveTime)以后释放maximumPoolSize-corePoolSize这些线程
* <p>
* 提示:
* new LinkedBlockingDeque<>() 默认是Integer.MAX_VALUE。可能导致内存不够 需要根据压测结果自己指定
*/
public static ThreadPoolExecutor executor01 = new ThreadPoolExecutor(10
, 200
, 10
, TimeUnit.SECONDS
, new LinkedBlockingDeque<>()
, Executors.defaultThreadFactory()
, new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
System.out.println("main方法...start");
// executor.execute(); //无法获取任务返回值
Future<Object> submit = executor.submit(new Callable01());//可以获取任务返回值
Object o = null;
try {
o = submit.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("main方法...end == >" + o);
}
/**
* Callable<Object> ==>Object对应需要返回的结果
*/
public static class Callable01 implements Callable<Object> {
@Override
public Object call() throws Exception {
System.out.println("当前线程---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果---" + num);
return num;
}
}
}
线程池几种类型
- Executors.newCachedThreadPool(); //可缓存的线程池 core是0,所有都可以回收
- Executors.newFixedThreadPool(10); //定长线程池,固定大小不可回收
- Executors.newSingleThreadExecutor(); // core是1 单线程池
- Executors.newScheduledThreadPool(10);//定时任务线程池
创建线程几种方式的区别
- 第1、2两种方式不能获取返回值,第3种可以获取返回值
- 第1、2、3种方式不能进行资源控制
- 第4种可以进行资源控制,性能稳定
使用线程池的优点
- 降低资源消耗
- 提高响应速度
- 提供线程的可管理性
线程上下文切换(Thread Context Switch)
因为以下一些原因导致 cpu 不再执行当前的线程,转而执行另一个线程的代码
- 线程的 cpu 时间片用完
- 垃圾回收
- 有更高优先级的线程需要运行
- 线程自己调用了 sleep、yield、wait、join、park、synchronized、lock 等方法
当 Context Switch 发生时,需要由操作系统保存当前线程的状态,并恢复另一个线程的状态,Java 中对应的概念 就是程序计数器(Program Counter Register),它的作用是记住下一条 jvm 指令的执行地址,是线程私有的
- 状态包括程序计数器、虚拟机栈中每个栈帧的信息,如局部变量、操作数栈、返回地址等
- Context Switch 频繁发生会影响性能
start与run
public class Test {
public static void main(String[] args) {
Thread thread = new Thread("t1") {
@Override
public void run() {
System.out.println("running...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
// thread.run();
thread.start();
System.out.println("do other things...");
}
}
小结
- 直接调用 run 是在主线程中执行了 run,没有启动新的线程
- 使用 start 是启动新的线程,通过新的线程间接执行 run 中的代码
sleep与yield
sleep
- 调用sleep会让当前线程从Running进入Timed Waiting状态(阻塞)
- 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出
InterruptedException - 睡眠结束后的线程未必会立刻得到执行
- 建议用TimeUnit的sleep代替Thread的sleep来获得更好的可读性
yield
- 调用yield会让当前线程从Running进入Runnable就绪状态,然后调度执行其它线程
- 具体的实现依赖于操作系统的任务调度器
线程优先级
- 线程优先级会提示(hint)调度器优先调度该线程,但它仅仅是一个提示,调度器可以忽略它
- 如果cpu比较忙,那么优先级高的线程会获得更多的时间片,但cpu闲时,优先级几乎没作用
JUC强大辅助类
减少计数CountDownLatch
public class Test {
//6个同学陆续离开教室之后,班长锁门
public static void main(String[] args) throws InterruptedException {
//创建CountDownLatch对象,设置初始值
CountDownLatch countDownLatch = new CountDownLatch(6);
//6个同学陆续离开教室之后
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "号同学离开了教室");
//计数 -1
countDownLatch.countDown();
}, String.valueOf(i)).start();
}
//等待
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "班长锁门走人");
}
}
循环栅栏CyclicBarrier
public class Test {
//集齐7颗龙珠召唤神龙
public static void main(String[] args) throws InterruptedException {
//创建CyclicBarrier对象,设置初始值
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
System.out.println("***集齐7颗龙珠就可以召唤神龙");
});
//集齐7颗龙珠过程
for (int i = 1; i <= 7; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "星龙珠被收集到了");
//等待
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}, String.valueOf(i)).start();
}
}
}
信号量Semaphore
public class Test {
//模拟5件商品出售与退货
public static void main(String[] args) throws InterruptedException {
//创建Semaphore,设置许可数量
Semaphore semaphore = new Semaphore(5);
//模拟6辆汽车
for (int i = 1; i <= 10; i++) {
new Thread(() -> {
try {
//出售
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "号商品已出售");
//模拟退货
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//退货
semaphore.release();
System.out.println(Thread.currentThread().getName() + "号商品已退货");
}
}, String.valueOf(i)).start();
}
}
}
读写锁
一个资源可以被多个线程访问,或者可以被一个写线程访问,但是不能同时存在读写线程,读写互斥,读读共享的
//资源类
class MyCache {
//创建map集合
private volatile Map<String, Object> map = new HashMap<>();
//创建读写锁对象
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
//放数据
public void put(String key, Object value) {
//添加写锁
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "正在写操作" + key);
//暂停一会
TimeUnit.MICROSECONDS.sleep(300);
//放数据
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "写完了" + key);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
}
}
//放数据
public Object get(String key) {
//添加读锁
readWriteLock.readLock().lock();
Object result = null;
try {
System.out.println(Thread.currentThread().getName() + "正在读取操作" + key);
//暂停一会
TimeUnit.MICROSECONDS.sleep(300);
//放数据
result = map.get(key);
System.out.println(Thread.currentThread().getName() + "取完了" + key);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
return result;
}
}
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
//创建线程放数据
for (int i = 0; i < 5; i++) {
final int num = i;
new Thread(() -> {
myCache.put(num + "", num + "");
}, String.valueOf(i)).start();
}
//创建线程取数据
for (int i = 0; i < 5; i++) {
final int num = i;
new Thread(() -> {
myCache.get(num + "");
}, String.valueOf(i)).start();
}
}
}
- 读写锁对象:
ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); - 读锁(共享锁):
readWriteLock.readLock().lock(); - 写锁(独占锁):
readWriteLock.writeLock().lock()
优点:
- 读读可以共享,提升性能,可以同时多人进行读操作
缺点:
- 造成锁饥饿,一直读,没有写操作
- 读的时候,不能写,只有读完成之后,才可以写,写操作可以读
锁降级
- 写锁降级为读锁
public class Test {
public static void main(String[] args) throws InterruptedException {
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
writeLock.lock();
System.out.println("获取写锁");
readLock.lock();
System.out.println("获取读锁");
writeLock.unlock();
readLock.unlock();
}
}
BlockingQueue阻塞队列
当队列是空的时,从队列中获取元素的操作是阻塞 队列是满的时,向队列中添加元素的操作是阻塞
常用阻塞队列
- 数组结构组成的有界阻塞队列
BlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(3); - 由链表结构组成的有界阻塞队列
BlockingQueue<String> linkedBlockingQueue = new LinkedBlockingQueue<>(); - 不存储任何元素的阻塞队列,即放一个取一个
BlockingQueue<String> synchronousQueue = new SynchronousQueue<>();
核心方法
| 方法类型 | 抛出异常 | 特殊值 | 阻塞 | 超时 |
|---|---|---|---|---|
| 插入 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
| 移除 | remove(e) | poll() | take() | poll(time,unit) |
| 检查 | element() | peek() | 不可用 | 不可用 |
CompletableFuture异步编排
创建异步对象
提供了四个静态方法创建异步操作
- public static CompletableFuture runAsync(Runnable runnable) //无返回值
- public static CompletableFuture runAsync(Runnable runnable,Executor executor) //无返回值,可传入自定义的线程池对象
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture.runAsync(() -> {
System.out.println("当前线程---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果---" + num);
}, executor);
System.out.println("main方法...end");
}
}
- public static CompletableFuture supplyAsync(Supplier supplier)//有返回值
- public static CompletableFuture supplyAsync(Supplier supplier,Executor executor)//返回值,可传入自定义的线程池对象
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果---" + num);
return num;
}, executor);
Integer integer = 0;
try {
integer = future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("main方法...end" + integer);
}
}
异步完成回调与异常感知
whenComplete只可以进行感知结果和异常,但是无法对结果进行修改
- public CompletableFuture whenComplete(BiConsumer<? super T, ? super Throwable> action) 执行当前任务的线程继续执行
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果---" + num);
return num;
}, executor).whenComplete((res, exception) -> {
System.out.println("结果是-->" + res + "异常是-->" + exception);
});
Integer integer = 0;
try {
integer = future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("main方法...end" + integer);
}
}
- public CompletableFuture whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action) 继续提交给线程池进行处理
- public CompletableFuture whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor) 继续提交给线程池进行处理,指定自定义线程池
- public CompletableFuture exceptionally(Function<Throwable, ? extends T> fn) 处理异常情况
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程---" + Thread.currentThread().getName());
int num = 10 / 0;
System.out.println("运行结果---" + num);
return num;
}, executor).whenComplete((res, exception) -> {
System.out.println("结果是-->" + res + "异常是-->" + exception);
}).exceptionally((exception) -> {
//可以感知异常,进行设置默认值
return 10;
});
Integer integer = 0;
try {
integer = future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("main方法...end" + integer);
}
}
handle可对结果进行后续处理
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果---" + num);
return num;
}, executor).handle((res, exception) -> {
if (res != null) {
return res * 2;
}
if (exception != null) {
return res;
}
return 0;
});
Integer integer = 0;
try {
integer = future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("main方法...end" + integer);
}
}
线程串行化
- public CompletableFuture thenRun(Runnable action)
- public CompletableFuture thenRunAsync(Runnable action)
- public CompletableFuture thenRunAsync(Runnable action,Executor executor) 不能获取上一步的执行结果,无返回值
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果---" + num);
return num;
}, executor);
future.thenRunAsync(() -> {
System.out.println("任务2启动了....");
}, executor);
System.out.println("main方法...end");
}
}
- public CompletableFuture thenAccept(Consumer<? super T> action)
- public CompletableFuture thenAcceptAsync(Consumer<? super T> action)
- public CompletableFuture thenAcceptAsync(Consumer<? super T> action,Executor executor)能接收上一个线程的执行结果,无返回值
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果---" + num);
return num;
}, executor);
future.thenAcceptAsync((res) -> {
System.out.println("任务2启动了...."+res);
}, executor);
System.out.println("main方法...end");
}
}
- public CompletableFuture thenApply(Function<? super T,? extends U> fn)
- public CompletableFuture thenApplyAsync(Function<? super T,? extends U> fn)
- public CompletableFuture thenApplyAsync(Function<? super T,? extends U> fn, Executor executor) 能接收上一个线程的执行结果,有返回值
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果---" + num);
return num;
}, executor);
CompletableFuture<Integer> future1 = future.thenApplyAsync((res) -> {
System.out.println("任务2启动了...." + res);
return res * 2;
}, executor);
Integer integer = 0;
try {
integer = future1.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("main方法...end" + integer);
}
}
两任务组合-都要完成
- public CompletableFuture runAfterBoth(CompletionStage<?> other,Runnable action)
- public CompletableFuture runAfterBothAsync(CompletionStage<?> other,Runnable action)
- public CompletableFuture runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor executor) 组合两个future,不需要获取future的结果,只需要两个future处理完任务后,处理该任务
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程1---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果1---" + num);
return num;
}, executor);
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程1---" + Thread.currentThread().getName());
int num = 10 / 5;
System.out.println("运行结果1---" + num);
return num;
}, executor);
future.runAfterBothAsync(future1,()->{
System.out.println("任务3开始");
},executor);
System.out.println("main方法...end");
}
}
- public < U> CompletableFuture< Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action)
- public CompletableFuture thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action)
- public CompletableFuture thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action,Executor executor) 组合两个future,获取两个future任务的返回结果,然后处理任务,没有返回值
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程1---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果1---" + num);
return num;
}, executor);
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程1---" + Thread.currentThread().getName());
int num = 10 / 5;
System.out.println("运行结果1---" + num);
return num;
}, executor);
future.thenAcceptBothAsync(future1, (res1, res2) -> {
System.out.println("第一个结果的返回值" + res1 + "第二个结果的返回值" + res2);
}, executor);
System.out.println("main方法...end");
}
}
- public <U,V> CompletableFuture thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)
- public <U,V> CompletableFuture thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)
- public <U,V> CompletableFuture thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn, Executor executor) 组合两个future,获取两个future的返回结果,并返回当前任务的返回值
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程1---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果1---" + num);
return num;
}, executor);
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程1---" + Thread.currentThread().getName());
int num = 10 / 5;
System.out.println("运行结果1---" + num);
return num;
}, executor);
CompletableFuture<Integer> future2 = future.thenCombineAsync(future1, (res1, res2) -> {
System.out.println("第一个结果的返回值" + res1 + "第二个结果的返回值" + res2);
return res1 + res2;
}, executor);
Integer integer = 0;
try {
integer = future2.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("main方法...end" + integer);
}
}
两任务组合-单个完成
- public CompletableFuture runAfterEither(CompletionStage<?> other,Runnable action)
- public CompletableFuture runAfterEitherAsync(CompletionStage<?> other,Runnable action)
- public CompletableFuture runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor) 组合两个future,两个任务有一个任务执行完,不需要获取返回结果,处理任务没有新的返回结果
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程1---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果1---" + num);
return num;
}, executor);
CompletableFuture< Integer> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
System.out.println("当前线程1---" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
int num = 10 / 5;
System.out.println("运行结果1---" + num);
return num;
}, executor);
future.runAfterEitherAsync(future1, () -> {
System.out.println("任务3开始....");
}, executor);
System.out.println("main方法...end");
}
}
- public CompletableFuture acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)
- public CompletableFuture acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action)
- public CompletableFuture acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action,Executor executor) 两个任务有一个任务执行完,获取它的返回结果,处理任务没有新的返回结果
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程1---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果1---" + num);
return num;
}, executor);
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
System.out.println("当前线程1---" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
int num = 10 / 5;
System.out.println("运行结果1---" + num);
return num;
}, executor);
future.acceptEitherAsync(future1, (res) -> {
System.out.println("任务返回结果" + res);
}, executor);
System.out.println("main方法...end");
}
}
- public CompletableFuture applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)
- public CompletableFuture applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn)
- public CompletableFuture applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn,Executor executor) 两个任务有一个任务执行完,获取它的返回结果,处理任务并返回新的返回结果
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程1---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果1---" + num);
return num;
}, executor);
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
System.out.println("当前线程1---" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
int num = 10 / 5;
System.out.println("运行结果1---" + num);
return num;
}, executor);
CompletableFuture<Integer> future2 = future.applyToEitherAsync(future1, (res) -> {
System.out.println("任务返回结果" + res);
return res * 2;
}, executor);
Integer integer = 0;
try {
integer = future2.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("main方法...end" + integer);
}
}
多任务组合
- public static CompletableFuture allOf(CompletableFuture<?>... cfs) 等待所有结果完成
public class Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
System.out.println("main方法...start");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程1---" + Thread.currentThread().getName());
int num = 10 / 2;
System.out.println("运行结果1---" + num);
return num;
}, executor);
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
System.out.println("当前线程1---" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
int num = 10 / 5;
System.out.println("运行结果1---" + num);
return num;
}, executor);
CompletableFuture<Void> allOf = CompletableFuture.allOf(future, future1);
try {
// allOf.get();
System.out.println("第一个返回结果" + future.get() + "第二个返回结果" + future1.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
- public static CompletableFuture anyOf(CompletableFuture<?>... cfs) 一个任务完成即可
public class Test { public static ExecutorService executor = Executors.newFixedThreadPool(10); public static void main(String[] args) { System.out.println("main方法...start"); CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { System.out.println("当前线程1---" + Thread.currentThread().getName()); int num = 10 / 2; System.out.println("运行结果1---" + num); return num; }, executor); CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(3000); System.out.println("当前线程2---" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } int num = 10 / 5; System.out.println("运行结果2---" + num); return num; }, executor); CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future, future1); try { anyOf.get(); System.out.println("返回结果..."); //此处打印先于 当前线程2--- } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }