# concurrency-study **Repository Path**: Protector_hui/concurrency-study ## Basic Information - **Project Name**: concurrency-study - **Description**: 学习书籍《Java多线程编程核心技术》 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-07-29 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 目录 - [线程状态转移图](#线程状态转移图) - [thread.start() & thread.run() 的区别](#thread.start&thread.run的区别) - [getId() 的作用](#getId()) - [停止线程](#停止线程) - [isInterrupted](#isInterrupted()) - [yield() 方法](#yield()) - [实例变量非线程安全的例子](#实例变量非线程安全的例子) - [synchronized](#synchronized) - [多个对象多个锁](#多个对象多个锁) - [脏读](#脏读) - [synchronized锁重入](#synchronized锁重入) - [synchronized同步语句块](#synchronized同步语句块) - [静态同步synchronized 方法与synchronized(class) 代码块](#静态同步synchronized方法与synchronized(class)代码块) - [死锁](#死锁) - [volatile](#volatile) - [线程间通信](#线程间通信) - [wait()](#wait()) - [notify()](#notify()) - [notifyAll()](#notifyAll()) - [当 interrupt() 遇到 wait()](#当interrupt()遇到wait()) - [notify() 和 notifyAll()](#notify()和notifyAll()) - [生产者/消费者](#生产者/消费者) - [多生产者与多消费者导致的死锁](#多生产者与多消费者导致的死锁) - [因条件判断引起的线程异常](#因条件判断引起的线程异常) - [join()](#join()) - [join(long)](#join(long)) - [ThreadLocal](#ThreadLocal) - [Lock](#Lock) - [Reentrantlock](#Reentrantlock) - [Condition的 await & signal](#Condition的await&signal) - [多个Condition](#多个Condition) - [公平锁与非公平锁](#公平锁与非公平锁) - [getHoldCount()](#getHoldCount()) - [getQueueLength()](#getQueueLength()) - [getWaitQueueLength(Condition condition)](#getWaitQueueLength) - [tryLock()](#tryLock()) - [tryLock(long timeout, TimeUnit unit)](#tryLock2) - [awaitUninterruptibly()](#awaitUninterruptibly()) - [ReentrantReadWriteLock类](#ReentrantReadWriteLock类) - [读 + 读(共享锁)](#读+读(共享锁)) - [写 + 写(排他锁)](#写+写(排他锁)) - [读 + 写(排他锁)](#读+写(排他锁)) - [StampedLock](#StampedLock) - [单例模式与多线程](#单例模式与多线程) - [饿汉模式](#饿汉模式) - [懒汉模式](#懒汉模式) - [懒汉模式 - 方法锁](#懒汉模式2) - [懒汉模式 - 代码块双重判断锁](#懒汉模式3) - [懒汉模式 - 代码块双重判断锁 + volatile](#懒汉模式4) - [使用enum枚举类实现单例模式](#使用enum枚举类实现单例模式) - [Concurrent集合](#Concurrent集合) - [ExecutorService线程池](#ExecutorService线程池) - [newCachedThreadPool](#newCachedThreadPool) - [newFixedThreadPool](#newFixedThreadPool) - [newSingleThreadExecutor](#newSingleThreadExecutor) - [newScheduledThreadPool](#newScheduledThreadPool) - [一次性任务,在指定延迟时间后执行一次(.schedule)](#一次性任务,在指定延迟时间后执行一次(.schedule)) - [定时任务,每x秒执行一次(.scheduleAtFixedRate)](#定时任务,每x秒执行一次(.scheduleAtFixedRate)) - [定时任务,每x秒执行一次,线程任务执行时间大于x秒后的现象(.scheduleAtFixedRate)](#定时任务,每x秒执行一次,线程任务执行时间大于x秒后的现象(.scheduleAtFixedRate)) - [定时任务,每x秒执行一次,线程任务执行时间大于x秒后的现象(.scheduleWithFixedDelay)](#定时任务,每x秒执行一次,线程任务执行时间大于x秒后的现象(.scheduleWithFixedDelay)) - [ExecutorService方法介绍](#ExecutorService方法介绍) - [awaitTermination(long timeout, TimeUnit unit)](#awaitTermination) - [invokeAll(Collection> tasks)](#invokeAll) - [invokeAll(Collection> tasks, long timeout, TimeUnit unit)](#invokeAll2) - [invokeAny(Collection> tasks)](#invokeAny) - [invokeAny(Collection> tasks, long timeout, TimeUnit unit)](#invokeAny2) - [shutdown()](#shutdown()) - [isShutdown()](#isShutdown()) - [isTerminated()](#isTerminated()) - [shutdownNow()](#shutdownNow()) - [submit(Callable task)](#submit) - [submit(Runnable task)](#submit2) - [submit(Runnable task, T result)](#submit3) - [Future](#Future) - [get()](#get()) - [get(long timeout, TimeUnit unit)](#get2()) - [参考资料](#参考资料) - [代码](#代码) # 线程状态转移图 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200731172239679.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70) # thread.start() & thread.run() 的区别 ==**示例**== ```java /** * thread.start() 和 thread.run()的区别 */ public class StartAndRun implements Runnable{ @Override public void run() { System.out.println("Thread name: " + Thread.currentThread().getName()); } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new StartAndRun()); System.out.println("-------thread.run()-------"); thread.run(); Thread.sleep(1000); System.out.println("-------thread.start()-------"); thread.start(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200801194519651.png) > 代码:chapter2#StartAndRun # getId() 的作用 getId() 方法的作用是取得线程的唯一标识。 ==**示例**== ```java public class GetId implements Runnable{ @Override public void run() { System.out.println("Run thread id: " + Thread.currentThread().getId()); } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new GetId()); thread.start(); Thread.sleep(1000); System.out.println("Main thread id: " + Thread.currentThread().getId()); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200801195558682.png) > 代码:chapter3#GetId # 停止线程 在Java中有3种方法可以终止正在运行的线程: 1. 线程正常执行结束。 2. 使用**stop、suspend、resume**强制终止线程。**(这三个方法都是过期方法,不推荐使用)** 3. 使用**interrupt**方法中断线程。 **interrupt()** 方法仅仅是在当前线程中打了一个停止的标记,并不是真的停止线程。 ## isInterrupted() **isInterrupted()** 方法测试线程是否已经是中断状态,但不清除状态标志。 ==**示例**== ```java public class IsInterrupted implements Runnable { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("i = " + i); } } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new IsInterrupted()); System.out.println("Thread starting.."); thread.start(); Thread.sleep(1); System.out.println("Thread interrupting.."); thread.interrupt(); System.out.println("Thread isInterrupt = " + thread.isInterrupted()); Thread.sleep(1000); System.out.println("Thread isInterrupt = " + thread.isInterrupted()); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200801202633667.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70) > 代码:chapter4#Interrupted # yield() 方法 **yield()** 方法的作用是:**放弃当前的CPU资源,将它让给其他的任务去占用CPU执行时间**。但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片。 ==**注释掉:Thread.yeild() 方法**== ==**示例**== ```java public class Yield implements Runnable { @Override public void run() { for (int i = 1; i <= 10; i++) { System.out.println("sub thread, i = " + i); } } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Yield()); thread.start(); for (int i = 1; i <= 10; i++) { System.out.println("Main thread, i = " + i); // Thread.yield(); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200801204638788.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70) ==**不注释:Thread.yeild() 方法**== ==**示例**== ```java public class Yield implements Runnable { @Override public void run() { for (int i = 1; i <= 10; i++) { System.out.println("sub thread, i = " + i); } } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Yield()); thread.start(); for (int i = 1; i <= 10; i++) { System.out.println("Main thread, i = " + i); Thread.yield(); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200801204800915.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70) > 代码:chapter5#Yield # 实例变量非线程安全的例子 - 如果实例变量是:**方法内部的私有变量**,则不存在“非线程安全”的问题。这是方法内部的变量是**私有的**特性所造成的。 - 如果多个线程共同访问同一个对象的实例变量,则有可能出现“非线程安全”的问题。 ==**示例**== ```java public class TestClass { private int num = 0; public void getTargetName(String targetName) throws InterruptedException { if ("ThreadA".equals(targetName)) { num = 100; System.out.println("ThreadA is end!"); Thread.sleep(1000); } else { num = 200; System.out.println("ThreadB is end!"); Thread.sleep(1000); } System.out.println("num result is " + num); } public static void main(String[] args) { TestClass testClass = new TestClass(); Thread threadA = new Thread(() -> { try { testClass.getTargetName("ThreadA"); } catch (InterruptedException e) { e.printStackTrace(); } }); threadA.start(); Thread threadB = new Thread(() -> { try { testClass.getTargetName("ThreadB"); } catch (InterruptedException e) { e.printStackTrace(); } }); threadB.start(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200801221148216.png) > 代码:chapter6#TestClass # synchronized **关键字synchronized**可以保证在同一刻,只有一个线程可以执行某一个方法或某一个代码块。它包含两个特征:**互斥性和可见性**。同步synchronized不仅可以解决一个线程看到对象处于不一致的状态,还可以保证进入同步方法或者同步代码块的每个线程,都看到由同一个锁保护之前所有的修改效果。 ## 多个对象多个锁 多个对象多个锁,**关键字synchronized** 取得的锁都是**对象锁**,而不是把一段代码或方法(函数)当做锁。 ==**示例**== ```java /** * 创建两个SynchronizedOne对象,分别用两个线程调用。 * SynchronizedOne对象的方法加了关键字:synchronized,但是结果还是异步的 */ public class SynchronizedOne { private int num = 0; synchronized public void getTargetName(String targetName) throws InterruptedException { if ("ThreadA".equals(targetName)) { num = 100; System.out.println("ThreadA is end!"); Thread.sleep(1000); } else { num = 200; System.out.println("ThreadB is end!"); Thread.sleep(1000); } System.out.println("num result is " + num); } public static void main(String[] args) { SynchronizedOne synchronizedOne = new SynchronizedOne(); Thread threadA = new Thread(() -> { try { synchronizedOne.getTargetName("ThreadA"); } catch (InterruptedException e) { e.printStackTrace(); } }); threadA.start(); SynchronizedOne synchronizedTwo = new SynchronizedOne(); Thread threadB = new Thread(() -> { try { synchronizedTwo.getTargetName("ThreadB"); } catch (InterruptedException e) { e.printStackTrace(); } }); threadB.start(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200801214733382.png) > 代码:chapter7#SynchronizedOne ==**使用同一个对象后**== ==**示例**== ```java public class SynchronizedTwo { private int num = 0; synchronized public void getTargetName(String targetName) throws InterruptedException { if ("ThreadA".equals(targetName)) { num = 100; System.out.println("ThreadA is end!"); Thread.sleep(1000); } else { num = 200; System.out.println("ThreadB is end!"); Thread.sleep(1000); } System.out.println("num result is " + num); } public static void main(String[] args) { SynchronizedTwo synchronizedTwo = new SynchronizedTwo(); Thread threadA = new Thread(() -> { try { synchronizedTwo.getTargetName("ThreadA"); } catch (InterruptedException e) { e.printStackTrace(); } }); threadA.start(); Thread threadB = new Thread(() -> { try { synchronizedTwo.getTargetName("ThreadB"); } catch (InterruptedException e) { e.printStackTrace(); } }); threadB.start(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200801214718837.png) > 代码:chapter7#SynchronizedTwo ## 脏读 **线程A**先持有**对象A**的**锁**,**线程B**可以以**异步的方式**调用**对象A中**的**非synchronized**类型的方法。若synchronized和非synchronized方法调用了同一个实例变量,则有可能出现脏读的情况。 ==**示例**== ```java /** * 主线程 启动 子线程 去修改username + password * 在子线程修改的过程中(Thread.sleep(1000)),主线程读取对象中的username + password * 则有几率出现脏读的情况 */ public class SynchronizedThree { private String userName = "admin"; private String password = "admin"; synchronized public void setValue(String userName, String password) throws InterruptedException { this.userName = userName; Thread.sleep(1000); this.password = password; System.out.println("setValue method -> userName = " + this.userName + ", password = " + this.password); } public void getValue() { System.out.println("getValue method -> userName = " + this.userName + ", password = " + this.password); } public static void main(String[] args) throws InterruptedException { SynchronizedThree synchronizedThree = new SynchronizedThree(); Thread thread = new Thread(() -> { try { synchronizedThree.setValue("root", "root"); } catch (InterruptedException e) { e.printStackTrace(); } }); thread.start(); Thread.sleep(10); synchronizedThree.getValue(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200801220354577.png) > 代码:chapter7#SynchronizedThree ==**两个方法都加上关键字synchronized**== ==**示例**== ```java public class SynchronizedFour { private String userName = "admin"; private String password = "admin"; synchronized public void setValue(String userName, String password) throws InterruptedException { this.userName = userName; Thread.sleep(1000); this.password = password; System.out.println("setValue method -> userName = " + this.userName + ", password = " + this.password); } synchronized public void getValue() { System.out.println("getValue method -> userName = " + this.userName + ", password = " + this.password); } public static void main(String[] args) throws InterruptedException { SynchronizedFour synchronizedFour = new SynchronizedFour(); Thread thread = new Thread(() -> { try { synchronizedFour.setValue("root", "root"); } catch (InterruptedException e) { e.printStackTrace(); } }); thread.start(); Thread.sleep(10); synchronizedFour.getValue(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020080122054241.png) > 代码:chapter7#SynchronizedFour ## synchronized锁重入 synchronized 方法/块的内部调用本类的其他synchronized 方法/块时,是永远可以得到锁的。父子类继承也符合synchronized锁重入的条件。 ==**示例**== ```java /** * Main & Sub类的方法都加上关键字synchronized * Sub类循环调用Main的方法 */ public class Main { public int i = 10; synchronized public void operateIMainMethod() throws InterruptedException { i--; System.out.println("Main print i = " + i); Thread.sleep(1000); } } ``` ```java public class Sub extends Main { synchronized public void operateISubMethod() throws InterruptedException { while (i > 0) { i--; System.out.println("Sub print i = " + i); Thread.sleep(1000); this.operateIMainMethod(); } } public static void main(String[] args) { Sub sub = new Sub(); Thread thread = new Thread(() -> { try { sub.operateISubMethod(); } catch (InterruptedException e) { e.printStackTrace(); } }); thread.start(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200802161715328.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70) > 代码:chapter8 ## synchronized同步语句块 ==**示例**== ```java /** * 加了关键字synchronized的代码块内的执行顺序是:同步的 * 没有加关键字synchronized的代码块内执行顺序是:异步的 */ public class Task { private String taskName; public void logTaskName(String inputTaskName) throws InterruptedException { System.out.println("Begin!"); Thread.sleep(1000); synchronized (this) { this.taskName = inputTaskName; System.out.println("The task name result is " + this.taskName + ";The input task name is " + inputTaskName); System.out.println("End!"); } } public static void main(String[] args) { Task task = new Task(); Thread threadA = new Thread(() -> { try { task.logTaskName("A"); } catch (InterruptedException e) { e.printStackTrace(); } }); threadA.start(); Thread threadB = new Thread(() -> { try { task.logTaskName("B"); } catch (InterruptedException e) { e.printStackTrace(); } }); threadB.start(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200802164038564.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70) > 代码:chapter9#Task ## 静态同步synchronized 方法与synchronized(class) 代码块 - **关键字synchronized**可以加在**static静态方法**上,对当前的 **\*.java** 文件对应的**class类**进行持锁。 - synchronized static 和 synchronized(class) 的作用是一样的 - **关键字synchronized**可以加在**非static静态方法**上,是给当前的**对象**上锁。 ==**示例**== ```java /** * 两个线程调用的是两个对象内的同步方法 * 得到的结果总是同步的 */ public class Service { synchronized public static void printA() throws InterruptedException { System.out.println("Print A begin"); Thread.sleep(1000); System.out.println("Print A end"); } synchronized public static void printB() throws InterruptedException { System.out.println("Print B begin"); System.out.println("Print B end"); } public static void main(String[] args) { Service service1 = new Service(); Service service2 = new Service(); Thread threadA = new Thread(() -> { try { service1.printA(); } catch (InterruptedException e) { e.printStackTrace(); } }); threadA.start(); Thread threadB = new Thread(() -> { try { service2.printB(); } catch (InterruptedException e) { e.printStackTrace(); } }); threadB.start(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020080217122966.png) > 代码:chapter10#Service ==**去掉同步方法上的static**== ==**示例**== ```java /** * 去掉同步方法上的static * 得到的结果是异步的 * 这时候synchronized获得的锁是:对象锁 */ public class Service2 { synchronized public void printA() throws InterruptedException { System.out.println("Print A begin"); Thread.sleep(1000); System.out.println("Print A end"); } synchronized public void printB() throws InterruptedException { System.out.println("Print B begin"); System.out.println("Print B end"); } public static void main(String[] args) { Service2 service1 = new Service2(); Service2 service2 = new Service2(); Thread threadA = new Thread(() -> { try { service1.printA(); } catch (InterruptedException e) { e.printStackTrace(); } }); threadA.start(); Thread threadB = new Thread(() -> { try { service2.printB(); } catch (InterruptedException e) { e.printStackTrace(); } }); threadB.start(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200802171504853.png) > 代码:chapter10#Service2 ## 死锁 死锁产生的条件是:多线程各自持有不同的锁,并互相视图获取对方个已持有的锁,导致双方各自无限等待。 避免死锁的方法是:多线程获取锁的顺序要一致。 ==**示例**== ```java /** * 分别调用同一个对象的同一个方法,根据传入的值不同,走不同的流程。 * 流程中互相调用对方的锁,双方都在等对方释放锁,最终导致死锁。 */ public class DeadLock { public Object lock1 = new Object(); public Object lock2 = new Object(); public void logTaskName(String taskName) throws InterruptedException { /** * 从lock1 切换到 lock2 */ if ("A".equals(taskName)) { synchronized (lock1) { System.out.println("taskName = " + taskName); Thread.sleep(3000); synchronized (lock2) { System.out.println("lock1 -> lock2"); } } } /** * 从lock2 切换到 lock1 */ if ("B".equals(taskName)) { synchronized (lock2) { System.out.println("taskName = " + taskName); Thread.sleep(3000); synchronized (lock1) { System.out.println("lock2 -> lock1"); } } } } public static void main(String[] args) throws InterruptedException { DeadLock deadLock = new DeadLock(); Thread threadA = new Thread(() -> { try { deadLock.logTaskName("A"); } catch (InterruptedException e) { e.printStackTrace(); } }); Thread threadB = new Thread(() -> { try { deadLock.logTaskName("B"); } catch (InterruptedException e) { e.printStackTrace(); } }); threadA.start(); threadB.start(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020080420473671.png) > 代码:chapter12#DeadLock # volatile **关键字volatile** 的主要作用是:使变量在多个线程间可见。强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。 - volatile只能修饰于变量 - volatile能保证数据的**可见性**,但不能保证**原子性** 关键字volatile 主要使用的场合是在多个线程中可以感知实例变量被更改了,并且可以获得最新的值使用,也就是用多线程读取共享变量时可以获得最新值使用。 ## 参考资料 [线程安全(上)--彻底搞懂volatile关键字](https://www.cnblogs.com/kubidemanong/p/9505944.html) # 线程间通信 ## wait() - **作用**:使当前执行代码的线程进行等待,直到**接到通知**或**被中断**为止。 - 在调用 **wait()** 之前,线程必须获得该对象的**对象级别锁**,即:只能在同步方法或同步块中使用。 - **wait()** 方法可以使调用该方法的线程释放**共享资源的锁**,然后从运行状态退出,进入等待队列,直到被再次唤醒。 - **wait(long)**:当超过设定的时间还是没有其他线程唤醒此线程,则会自动唤醒。 ## notify() - 作用是:用来通知那些等待该对象的**对象锁**的其他线程。 - 调用notify()之前,也需要获得该对象的**对象级别锁**。 - 调用notify()之后,当前线程**不会**马上释放该对象锁,呈wait状态的线程也不能马上获取该对象锁,要等到执行notify()方法的线程将程序执行完,当前线程才会释放锁。 ## notifyAll() - notifyAll()方法可以使所有正在等待队列中等待**同一共享资源**的“全部”线程从等待状态退出,进入可运行状态。 - 一般优先级最高的线程最先执行, ==**示例**== ```java public class WaitAndNotify { public static void main(String[] args) throws InterruptedException { Object object = new Object(); // wait() Thread waitThread = new Thread(() -> { try { synchronized (object) { System.out.println("wait() -> begin"); object.wait(); System.out.println("wait() -> end"); } } catch (Exception e) { e.printStackTrace(); } }); // notify() Thread notifyThread = new Thread(() -> { try { synchronized (object) { System.out.println("notify() -> begin"); object.notify(); System.out.println("notify() -> end"); } } catch (Exception e) { e.printStackTrace(); } }); waitThread.start(); notifyThread.start(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200803223931521.png) > 代码:chapter11#WaitAndNotify ## 当 interrupt() 遇到 wait() 当线程处于 **wait()** 状态时,调用线程对象的 **interrupt()** 方法,会出现 **InterruptedException** 异常。 ==**示例**== ```java /** * 先让线程调用wait()方法,接着再调用interrupt()方法。 */ public class WaitAndInterrupted { public Object lockObject = new Object(); public void waitMethod() throws InterruptedException { synchronized (lockObject) { System.out.println("begin wait.."); lockObject.wait(); System.out.println("end wait.."); } } public static void main(String[] args) throws InterruptedException { WaitAndInterrupted waitAndInterrupted = new WaitAndInterrupted(); Thread thread = new Thread(() -> { try { waitAndInterrupted.waitMethod(); } catch (InterruptedException e) { System.out.println("Throw InterruptedException..."); } }); thread.start(); thread.interrupt(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200804210518817.png) > 代码:chapter13#WaitAndInterrupted ## notify() 和 notifyAll() **notify()** 只能随机唤醒“一个”线程。 **notifyAll()** 可以唤醒所有线程。 ==**示例1:notify()**== ```java public class NotifyOneThread { public void testNotifyOneThread(Object lock) throws InterruptedException { synchronized (lock) { System.out.println("begin wait.." + Thread.currentThread().getName()); lock.wait(); System.out.println("end wait.." + Thread.currentThread().getName()); } } public static void main(String[] args) throws InterruptedException { NotifyOneThread notifyOneThread = new NotifyOneThread(); Object lock = new Object(); Thread threadOne = new Thread(() -> { try { notifyOneThread.testNotifyOneThread(lock); } catch (InterruptedException e) { e.printStackTrace(); } }); Thread threadTwo = new Thread(() -> { try { notifyOneThread.testNotifyOneThread(lock); } catch (InterruptedException e) { e.printStackTrace(); } }); Thread threadThree = new Thread(() -> { try { notifyOneThread.testNotifyOneThread(lock); } catch (InterruptedException e) { e.printStackTrace(); } }); Thread notifyThread = new Thread(() -> { synchronized (lock) { lock.notify(); // lock.notifyAll(); } }); threadOne.start(); threadTwo.start(); threadThree.start(); Thread.sleep(1000); notifyThread.start(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200804212617894.png) ==**示例2:notifyAll()**== ```java public class NotifyOneThread { public void testNotifyOneThread(Object lock) throws InterruptedException { synchronized (lock) { System.out.println("begin wait.." + Thread.currentThread().getName()); lock.wait(); System.out.println("end wait.." + Thread.currentThread().getName()); } } public static void main(String[] args) throws InterruptedException { NotifyOneThread notifyOneThread = new NotifyOneThread(); Object lock = new Object(); Thread threadOne = new Thread(() -> { try { notifyOneThread.testNotifyOneThread(lock); } catch (InterruptedException e) { e.printStackTrace(); } }); Thread threadTwo = new Thread(() -> { try { notifyOneThread.testNotifyOneThread(lock); } catch (InterruptedException e) { e.printStackTrace(); } }); Thread threadThree = new Thread(() -> { try { notifyOneThread.testNotifyOneThread(lock); } catch (InterruptedException e) { e.printStackTrace(); } }); Thread notifyThread = new Thread(() -> { synchronized (lock) { // lock.notify(); lock.notifyAll(); } }); threadOne.start(); threadTwo.start(); threadThree.start(); Thread.sleep(1000); notifyThread.start(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200804212722931.png) > 代码:chapter14#NotifyOneThread ## 生产者/消费者 ### 多生产者与多消费者导致的死锁 **假死:所有线程都进入了等待状态。** 主要原因:调用 **notify()** 方法时,唤醒的是同类。即:生产者唤醒生产者,消费者唤醒消费者。 解决方法:调用 **notifyAll()** 方法,将所有等待的线程都唤醒。 ==**示例1:notify()**== ```java public class FakeDead { public String value = ""; // 生产者 public void producer(Object lock) throws InterruptedException { synchronized (lock) { while (!value.equals("")) { System.out.println("生产者: " + Thread.currentThread().getName() + " waiting☆"); lock.wait(); } System.out.println("生产者: " + Thread.currentThread().getName() + " running☆"); value = System.currentTimeMillis() + " --- " + Thread.currentThread().getName(); lock.notify(); } } // 消费者 public void consumer(Object lock) throws InterruptedException { synchronized (lock) { while (value.equals("")) { System.out.println("消费者: " + Thread.currentThread().getName() + " waiting★"); lock.wait(); } System.out.println("消费者: " + Thread.currentThread().getName() + " running★"); value = ""; lock.notify(); } } public static void main(String[] args) { Object lock = new Object(); FakeDead fakeDead = new FakeDead(); for (int i = 0; i < 2; i++) { // 创建消费者线程,循环的调用consumer方法 Thread consumerThread = new Thread(() -> { try { while (true) { fakeDead.consumer(lock); } } catch (InterruptedException e) { e.printStackTrace(); } }); // 创建生产者线程,循环的调用producer方法 Thread producerThread = new Thread(() -> { try { while (true) { fakeDead.producer(lock); } } catch (InterruptedException e) { e.printStackTrace(); } }); consumerThread.setName("consumer - " + i); producerThread.setName("producer - " + i); consumerThread.start(); producerThread.start(); } } } ``` *2个消费者 和 2个生产者 最后都进入了waiting状态了* ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200804221105942.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70) > 代码:chapter15#FakeDead ==**示例2:notifyAll()**== ```java public class FakeDead2 { public String value = ""; // 生产者 public void producer(Object lock) throws InterruptedException { synchronized (lock) { while (!value.equals("")) { System.out.println("生产者: " + Thread.currentThread().getName() + " waiting☆"); lock.wait(); } System.out.println("生产者: " + Thread.currentThread().getName() + " running☆"); value = System.currentTimeMillis() + " --- " + Thread.currentThread().getName(); lock.notifyAll(); } } // 消费者 public void consumer(Object lock) throws InterruptedException { synchronized (lock) { while (value.equals("")) { System.out.println("消费者: " + Thread.currentThread().getName() + " waiting★"); lock.wait(); } System.out.println("消费者: " + Thread.currentThread().getName() + " running★"); value = ""; lock.notifyAll(); } } public static void main(String[] args) { Object lock = new Object(); FakeDead2 fakeDead = new FakeDead2(); for (int i = 0; i < 2; i++) { // 创建消费者线程,循环的调用consumer方法 Thread consumerThread = new Thread(() -> { try { while (true) { fakeDead.consumer(lock); } } catch (InterruptedException e) { e.printStackTrace(); } }); // 创建生产者线程,循环的调用producer方法 Thread producerThread = new Thread(() -> { try { while (true) { fakeDead.producer(lock); } } catch (InterruptedException e) { e.printStackTrace(); } }); consumerThread.setName("consumer - " + i); producerThread.setName("producer - " + i); consumerThread.start(); producerThread.start(); } } } ``` *解决上面假死的情况* ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200804221420176.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70) > 代码:chapter15#FakeDead2 ### 因条件判断引起的线程异常 例子:使用一个生产者向堆栈List对象中放入数据,而多个消费者从List堆栈中取出数据。List的最大容量是:1。 ==**示例1:使用 if 判断条件**== ```java public class IfCondition { private List list = new ArrayList(1); /** * 数组大小 = 1 时,线程释放资源,进入等待 * 数组大小 != 1 时, 数组大小 + 1 */ public void push(Object lock) { synchronized (lock) { try { if (list.size() == 1) { lock.wait(); } list.add("anyString = " + Math.random()); lock.notify(); System.out.println("Current thread name = " + Thread.currentThread().getName() + " push = " + list.size()); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * 数组大小 = 0 时,线程释放资源,进入等待 * 数组大小 != 0 时, 数组大小 - 1 */ public void pop(Object lock) { synchronized (lock) { try { if (list.size() == 0) { lock.wait(); } list.remove(0); lock.notify(); System.out.println("Current thread name = " + Thread.currentThread().getName() + " pop = " + list.size()); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * 主线程 * * @param args */ public static void main(String[] args) throws InterruptedException { Object lock = new Object(); IfCondition ifCondition = new IfCondition(); /** * 一个生产者 */ Thread pushThread = new Thread(() -> { while (true) { ifCondition.push(lock); } }); pushThread.start(); Thread.sleep(1000); /** * 多个消费者 */ for (int i = 0; i < 3; i++) { Thread popThread = new Thread(() -> { while (true) { ifCondition.pop(lock); } }); popThread.setName("popThread - " + i); popThread.start(); } } } ``` *程序很容易就抛出异常* ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200808185411225.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70) > 代码:chapter16#IfCondition ==**示例2:使用 while 判断条件**== 除了 if 条件 改成 while 条件外,lock.notify() 也要改成 lock.notifyAll()。不然,解决了异常的问题,还会遇到死锁的问题。 ```java public class WhileCondition { private List list = new ArrayList(1); /** * 数组大小 = 1 时,线程释放资源,进入等待 * 数组大小 != 1 时, 数组大小 + 1 */ public void push(Object lock) { synchronized (lock) { try { while (list.size() == 1) { lock.wait(); } list.add("anyString = " + Math.random()); lock.notifyAll(); System.out.println("Current thread name = " + Thread.currentThread().getName() + " push = " + list.size()); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * 数组大小 = 0 时,线程释放资源,进入等待 * 数组大小 != 0 时, 数组大小 - 1 */ public void pop(Object lock) { synchronized (lock) { try { while (list.size() == 0) { lock.wait(); } list.remove(0); lock.notifyAll(); System.out.println("Current thread name = " + Thread.currentThread().getName() + " pop = " + list.size()); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * 主线程 * * @param args */ public static void main(String[] args) throws InterruptedException { Object lock = new Object(); WhileCondition ifCondition = new WhileCondition(); /** * 一个生产者 */ Thread pushThread = new Thread(() -> { while (true) { ifCondition.push(lock); } }); pushThread.start(); Thread.sleep(1000); /** * 多个消费者 */ for (int i = 0; i < 3; i++) { Thread popThread = new Thread(() -> { while (true) { ifCondition.pop(lock); } }); popThread.setName("popThread - " + i); popThread.start(); } } } ``` > 代码:chapter16#WhileCondition ## join() 在主线程创建并启动子线程后,如果子线程中要进行大量的耗时计算,主线程将会早于子线程结束。如果主线程需要等待子线程完成后完成,则可以使用:**join()** 方法。 **join()** 方法的作用是:使**子线程**正常执行线程任务,使得**主线程**进入阻塞,直到子线程执行完后再执行。 ### join(long) **方法join(long)**:设定等待的时间。 ```java public class Join { public void execute() throws InterruptedException { System.out.println("Begin"); Thread.sleep(1000); System.out.println("End"); } public static void main(String[] args) throws InterruptedException { Join join = new Join(); Thread thread = new Thread(() -> { try { join.execute(); } catch (InterruptedException e) { e.printStackTrace(); } }); thread.start(); thread.join(); System.out.println("Main thread end."); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200808193215267.png) > 代码:chapter17#Join ## ThreadLocal ThreadLocal:用于存放属于每个线程自己的值。 ```java public class ThreadLocalTest { private static ThreadLocal threadLocal = new ThreadLocal<>(); public static void main(String[] args) { Thread threadA = new Thread(() -> { testMethod(); }); Thread threadB = new Thread(() -> { testMethod(); }); threadA.setName("ThreadA"); threadB.setName("ThreadB"); threadA.start(); threadB.start(); } private static void testMethod() { System.out.println(Thread.currentThread().getName() + " beginning..."); threadLocal.set("My thread name is " + Thread.currentThread().getName()); try { Thread.sleep(5000); System.out.println("Test threadlocal in " + Thread.currentThread().getName() + "; My threadlocal value is " + threadLocal.get()); } catch (InterruptedException e) { e.printStackTrace(); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020080819472681.png) > 代码:chapter18#ThreadLocalTest # Lock ## ReentrantLock 使用**Reentrantlock**达到和**Synchronized**同样的效果。 ```java public class ReentrantLockTest { private Lock lock = new ReentrantLock(); public void methodA() { try { lock.lock(); System.out.println("Method A begin -> " + Thread.currentThread().getName()); Thread.sleep(2000); System.out.println("Method A end -> " + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void methodB() { try { lock.lock(); System.out.println("Method B begin -> " + Thread.currentThread().getName()); Thread.sleep(2000); System.out.println("Method B end -> " + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public static void main(String[] args) { ReentrantLockTest reentrantLockTest = new ReentrantLockTest(); for (int i = 0; i < 6; i++) { Thread threadA = new Thread(() -> { reentrantLockTest.methodA(); }); Thread threadB = new Thread(() -> { reentrantLockTest.methodB(); }); threadA.setName("ThreadA-" + i); threadB.setName("ThreadB-" + i); threadA.start(); threadB.start(); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200809085853846.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70) > 代码:chapter19#ReentrantLockTest ## Condition的await & signal **Reentrantlock** 配合 **Condition** 后,也可以实现像 **Synchronized** 配合 **wait & notify** 的 等待 & 通知的功能。 **不同点**: - 一个Lock对象中可以创建多个Condition(即对象监视器)实例,线程对象可以注册在指定的Condition中,从而可以有**选择性**地进行线程通知,在调度线程上更加灵活。 - notify() & notifyAll() 方法进行通知时,被通知的对象是由JVM随机选择的结果。 ```java public class ConditionTest { private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void await() { try { lock.lock(); System.out.println("Await begin time is " + new Date()); condition.await(); System.out.println("Await end time is " + new Date()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void signal() { lock.lock(); System.out.println("Signal begin time is " + new Date()); condition.signal(); System.out.println("Signal end time is " + new Date()); lock.unlock(); } public static void main(String[] args) throws InterruptedException { ConditionTest conditionTest = new ConditionTest(); Thread threadAwait = new Thread(() -> { conditionTest.await(); }); Thread threadSignal = new Thread(() -> { conditionTest.signal(); }); threadAwait.start(); Thread.sleep(3000); threadSignal.start(); } } ``` 到目前为止,**condition**的**await() & signal()/signalAll()** 实现的效果和 **wait() & notify()/notifyAll()** 一样。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200809092831112.png) > 代码:chapter20#ConditionTest ## 多个Condition 在同一个实例中,创建两个Condition对象,然后实现只通知其中某一个Condition对象。 ```java public class ConditionTest2 { private Lock lock = new ReentrantLock(); private Condition conditionA = lock.newCondition(); private Condition conditionB = lock.newCondition(); public void awaitA() { try { lock.lock(); System.out.println("Begin await A time is " + new Date() + "; Current thread name is " + Thread.currentThread().getName()); conditionA.await(); lock.unlock(); System.out.println("End await A time is " + new Date() + "; Current thread name is " + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } public void awaitB() { try { lock.lock(); System.out.println("Begin await B time is " + new Date() + "; Current thread name is " + Thread.currentThread().getName()); conditionB.await(); lock.unlock(); System.out.println("End await B time is " + new Date() + "; Current thread name is " + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } public void signalA() { lock.lock(); System.out.println("Begin signal A time is " + new Date()); conditionA.signalAll(); lock.unlock(); } public void signalB() { lock.lock(); System.out.println("Begin signal B time is " + new Date()); conditionB.signalAll(); lock.unlock(); } /** * 创建两个线程,两个Condition对象,进入wait状态 * 之后调用其中一个Condition对象的signalAll方法 * 查看最终结果是不是只有ConditionA对象会被唤醒 * @param args */ public static void main(String[] args) throws InterruptedException { ConditionTest2 conditionTest2 = new ConditionTest2(); Thread threadA = new Thread(() -> { conditionTest2.awaitA(); }); Thread threadB = new Thread(() -> { conditionTest2.awaitB(); }); threadA.setName("ThreadA"); threadB.setName("ThreadB"); threadA.start(); threadB.start(); Thread.sleep(1000); conditionTest2.signalA(); } } ``` 结果是:只有ConditionA被唤醒了,ConditionB依旧处于wait状态。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200809163848708.png) > 代码:chapter20#ConditionTest2 ## 公平锁与非公平锁 Lock分为“公平锁”和“非公平锁” - 公平锁:表示线程**获取锁的顺序**是按照线程加锁的顺序来分配的,先到先得。 - 非公平锁:就是线程获得锁的机会是**随机的**,这个可能会造成某些线程一直拿不到锁。 ==**示例1:公平锁**== ```java public class ConditionTest4 { // 注意这里创建Lock对象时,传入的参数是:true private Lock lock = new ReentrantLock(true); public void serviceMethod() { lock.lock(); System.out.println("Current Thread: " + Thread.currentThread().getName() + " is locking.."); lock.unlock(); } public static void main(String[] args) { ConditionTest4 conditionTest4 = new ConditionTest4(); // 创建10个线程 for (int i = 0; i < 10; i++) { Thread thread = new Thread(() -> { System.out.println("Current Thread: " + Thread.currentThread().getName() + " is running.."); conditionTest4.serviceMethod(); }); thread.setName("Thread-" + i); thread.start(); } } } ``` *结果是:总是按顺序获得锁* ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200809165347685.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70) > 代码:chapter20#ConditionTest3 ==**示例2:非公平锁**== ```java public class ConditionTest4 { // 注意这里创建Lock对象时,传入的参数是:false private Lock lock = new ReentrantLock(false); public void serviceMethod() { lock.lock(); System.out.println("Current Thread: " + Thread.currentThread().getName() + " is locking.."); lock.unlock(); } public static void main(String[] args) { ConditionTest4 conditionTest4 = new ConditionTest4(); // 创建10个线程 for (int i = 0; i < 10; i++) { Thread thread = new Thread(() -> { System.out.println("Current Thread: " + Thread.currentThread().getName() + " is running.."); conditionTest4.serviceMethod(); }); thread.setName("Thread-" + i); thread.start(); } } } ``` *结果是:不按顺序获得锁* ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020080916561316.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70) > 代码:chapter20#ConditionTest4 ## getHoldCount() **getHoldCount()**:查询当前线程保持此锁定的个数,也就是调用lock()方法的次数。 ```java public class GetHoldCount { private ReentrantLock lock = new ReentrantLock(); public void serviceMethod() { lock.lock(); System.out.println("ServiceMethod getHoldCount = " + lock.getHoldCount()); serviceMethod2(); lock.unlock(); } public void serviceMethod2() { lock.lock(); System.out.println("ServiceMethod2 getHoldCount = " + lock.getHoldCount()); serviceMethod3(); lock.unlock(); } public void serviceMethod3() { lock.lock(); System.out.println("ServiceMethod3 getHoldCount = " + lock.getHoldCount()); lock.unlock(); } public static void main(String[] args) { GetHoldCount getHoldCount = new GetHoldCount(); getHoldCount.serviceMethod(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200809170519770.png) > 代码:chapter20#GetHoldCount ## getQueueLength() **getQueueLength()**:返回正等待获取某锁的线程估计数。 ```java public class GetQueueLength { private ReentrantLock lock = new ReentrantLock(); public void serviceMethod() { try { lock.lock(); System.out.println("Thread: " + Thread.currentThread().getName() + " is locking..."); Thread.sleep(3000); lock.unlock(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) throws InterruptedException { GetQueueLength getQueueLength = new GetQueueLength(); for (int i = 0; i < 5; i++) { Thread thread = new Thread(() -> { getQueueLength.serviceMethod(); }); thread.setName("Thread-" + i); thread.start(); } Thread.sleep(1000); System.out.println("GetQueueLength = " + getQueueLength.lock.getQueueLength()); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200809171126627.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70) ## getWaitQueueLength(Condition condition) **getWaitQueueLength(Condition condition)**:返回等待与此锁相关的给定条件Condition的线程估计数。 eg: 有5个线程,每个线程都执行了同一个**condition**对象的 **await()** 方法,则调用getWaitQueueLength(Condition condition)方法时,返回的值为:5。 ```java /** * 创建5个线程,依次进入wait状态 */ public class GetWaitQueueLength { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void serviceMethod() { try { lock.lock(); System.out.println("Thread: " + Thread.currentThread().getName() + " is locking.."); condition.await(); lock.unlock(); } catch (InterruptedException e) { e.printStackTrace(); } } public void signalMethod() { lock.lock(); System.out.println("GetWaitQueueLength = " + lock.getWaitQueueLength(condition)); condition.signal(); System.out.println("After signal(), GetWaitQueueLength = " + lock.getWaitQueueLength(condition)); } public static void main(String[] args) throws InterruptedException { GetWaitQueueLength getWaitQueueLength = new GetWaitQueueLength(); for (int i = 0; i < 5; i++) { Thread thread = new Thread(() -> { getWaitQueueLength.serviceMethod(); }); thread.setName("Thread-" + i); thread.start(); } Thread.sleep(2000); getWaitQueueLength.signalMethod(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200809172318658.png) ## tryLock() 作用:仅在调用时锁定未被另一个线程保持的情况下,才获取该锁定。 ```java public class TryLock { private ReentrantLock lock = new ReentrantLock(); public void tryLockMethod() { if (lock.tryLock()) { System.out.println(Thread.currentThread().getName() + " 获得锁"); } else { System.out.println(Thread.currentThread().getName() + " 未获得锁"); } } public static void main(String[] args) { TryLock tryLock = new TryLock(); for (int i = 0; i < 2; i++) { Thread thread = new Thread(() -> { tryLock.tryLockMethod(); }); thread.setName("Thread-" + i); thread.start(); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200811072719777.png) > 代码:chapter20#TryLock ## tryLock(long timeout, TimeUnit unit) 作用是:如果锁定在给定的等待时间内没有被另一个线程保持,且当前线程未中断,则获取该锁定。 ## awaitUninterruptibly() 当使用condition.await()时,线程调用interrupt()后,会抛出异常。 当使用condition.awaitUninterruptibly()时,则不会抛出异常。 ```java public class AwaitUninterruptibly { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void awaitMethod() { try { lock.lock(); System.out.println("Before waiting.."); condition.await(); lock.unlock(); } catch (InterruptedException e) { e.printStackTrace(); } } public void awaitUninterruptibly() { lock.lock(); System.out.println("Before waiting..."); condition.awaitUninterruptibly(); lock.unlock(); } public static void main(String[] args) { AwaitUninterruptibly awaitUninterruptibly = new AwaitUninterruptibly(); Thread thread1 = new Thread(() -> { awaitUninterruptibly.awaitUninterruptibly(); }); thread1.start(); thread1.interrupt(); Thread thread = new Thread(() -> { awaitUninterruptibly.awaitMethod(); }); thread.start(); thread.interrupt(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020081107374434.png) > 代码:chapter20#AwaitUninterruptibly ## ReentrantReadWriteLock类 之前使用的**ReentrantLock**具有**完全互斥排他**的效果,即同一时间只有一个先线程可以执行lock.lock()后面的代码。这样虽然保证了实例变量的线程安全性,但效率却非常低下。 **ReentrantReadWriteLock**提供了两种锁:**共享锁 & 排他锁**。根据需要使用不同的锁,以提升代码的运行速度。 - 读 + 读(共享锁) - 读 + 写(排他锁) - 写 + 写(排他锁) ### 读 + 读(共享锁) ```java public class ReadAndRead { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void readMethod() throws InterruptedException { lock.readLock().lock(); System.out.println("获得读锁 -> " + Thread.currentThread().getName()); Thread.sleep(1000); lock.readLock().unlock(); } public static void main(String[] args) { ReadAndRead readAndRead = new ReadAndRead(); for (int i = 0; i < 2; i++) { Thread thread = new Thread(() -> { try { readAndRead.readMethod(); } catch (InterruptedException e) { e.printStackTrace(); } }); thread.setName("Thread-" + i); thread.start(); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200811075259550.png) > 代码:chapter21#ReadAndRead ### 写 + 写(排他锁) ```java public class WriteAndWrite { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void writeMethod() throws InterruptedException { lock.writeLock().lock(); System.out.println("获得写锁 -> " + Thread.currentThread().getName() + " " + new Date()); Thread.sleep(5000); lock.writeLock().unlock(); } public static void main(String[] args) { WriteAndWrite writeAndWrite = new WriteAndWrite(); for (int i = 0; i < 2; i++) { Thread thread = new Thread(() -> { try { writeAndWrite.writeMethod(); } catch (InterruptedException e) { e.printStackTrace(); } }); thread.setName("Thread-" + i); thread.start(); } } } ``` 5秒后才能获得写锁 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200811075619571.png) > 代码:chapter21#WriteAndWrite ### 读 + 写(排他锁) ```java public class WriteAndRead { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void writeMethod() throws InterruptedException { lock.writeLock().lock(); System.out.println("获得写锁 -> " + Thread.currentThread().getName() + " " + new Date()); Thread.sleep(5000); lock.writeLock().unlock(); } public void readMethod() { lock.readLock().lock(); System.out.println("获得读锁 -> " + Thread.currentThread().getName() + " " + new Date()); lock.readLock().unlock(); } public static void main(String[] args) { WriteAndRead writeAndRead = new WriteAndRead(); Thread threadWrite = new Thread(() -> { try { writeAndRead.writeMethod(); } catch (InterruptedException e) { e.printStackTrace(); } }); threadWrite.setName("Thread-Write"); threadWrite.start(); Thread threadRead = new Thread(() -> { writeAndRead.readMethod(); }); threadRead.setName("Thread-Read"); threadRead.start(); } } ``` 5秒后才能获得读锁 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200811080614552.png) > 代码:chapter21#WriteAndRead ## StampedLock 对于 **ReentrantReadWriteLock** 而言,只有读 + 读 是共享锁的,其他的都是互斥锁。 Java 8引入了新的读写锁,**StampedeLock**。不同之处在于:**StampedeLock** 在读的过程中允许写锁后写入。存在的问题是:之前读的数据可能会不一致,所以需要额外的操作来判断在读的过程中是否有写的操作。 ```java public class ReadAndWrite { private final StampedLock stampedLock = new StampedLock(); private String name = "name1"; public void writeName(String name) { // 获取写锁 long stamp = stampedLock.writeLock(); this.name = name; stampedLock.unlockWrite(stamp); } public void readName() throws InterruptedException { // 获得一个乐观锁,得到一个版本号 long stamp = stampedLock.tryOptimisticRead(); String tempName = this.name; // 让读线程睡0.1s,让写操作进行 Thread.sleep(1000); // 判断在读的过程中是否有写入的操作,如果版本号检验失败,即:读的期间值发生了改变,则通过悲观锁进行读操作 if (!stampedLock.validate(stamp)) { // 获取一个悲观锁,读锁 stamp = stampedLock.readLock(); tempName = this.name; stampedLock.unlockRead(stamp); } System.out.println("Name = " + tempName); } public static void main(String[] args) { ReadAndWrite readAndWrite = new ReadAndWrite(); Thread readThread = new Thread(() -> { try { readAndWrite.readName(); } catch (InterruptedException e) { e.printStackTrace(); } }); readThread.start(); Thread writeThread = new Thread(() -> { readAndWrite.writeName("name2"); }); writeThread.start(); } } ``` **区别** - 与 **ReadWriteLock** 相比,**StampedLock** 的代码更加复杂 - **StampedLock** 是不可重入锁,不能再一个线程中反复获取同一个锁 # 单例模式与多线程 ## 饿汉模式 饿汉模式:在类加载时就完成了初始化,项目启动时比较慢。但是是线程安全的。 ```java /** * 多个线程获取Hungry对象 * 对象的HashCode是一致的 */ public class Hungry { private static Hungry hungry = new Hungry(); public static Hungry getInstance() { return hungry; } public static void main(String[] args) { for (int i = 0; i < 5; i++) { Thread thread = new Thread(() -> { System.out.println(Thread.currentThread().getName() + " -> " + Hungry.getInstance().hashCode()); }); thread.setName("Thread-" + i); thread.start(); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200812080643259.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter22#Hungry ## 懒汉模式 懒汉模式 - 非线程安全版 ```java /** * 懒汉模式 - 非线程安全版 * 在new LazyPattern()前,让线程睡眠1s * 导致其他线程都能够进到 lazyPattern == null 的分支中,得到不同的LazyPattern对象 */ public class LazyPattern { private static LazyPattern lazyPattern; private LazyPattern() { } public static LazyPattern getInstance() throws InterruptedException { if (lazyPattern == null) { Thread.sleep(1000); lazyPattern = new LazyPattern(); } return lazyPattern; } public static void main(String[] args) { for (int i = 0; i < 5; i++) { Thread thread = new Thread(() -> { try { System.out.println(Thread.currentThread().getName() + " -> " + LazyPattern.getInstance().hashCode()); } catch (InterruptedException e) { e.printStackTrace(); } }); thread.setName("Thread-" + i); thread.start(); } } } ``` *结果:得到的对象不一致* ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200813075851430.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter22#LazyPattern ## 懒汉模式 - 方法锁 在方法上加**synchronized**关键字 ```java /** * 懒汉模式 - 极端线程安全版 * 直接给getInstance()方法加锁 * 即使后面对象已经被实例化了,在获取对象时,都需要获取锁、释放锁的操作 */ public class LazyPattern2 { private static LazyPattern2 lazyPattern; private LazyPattern2() { } public synchronized static LazyPattern2 getInstance() { if (lazyPattern == null) { lazyPattern = new LazyPattern2(); } return lazyPattern; } public static void main(String[] args) { for (int i = 0; i < 5; i++) { Thread thread = new Thread(() -> { System.out.println(Thread.currentThread().getName() + " -> " + LazyPattern2.getInstance().hashCode()); }); thread.setName("Thread-" + i); thread.start(); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200813080010671.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter22#LazyPattern2 ## 懒汉模式 - 代码块双重判断锁 ```java /** * 懒汉模式 - 双重判断锁 */ public class LazyPattern3 { private static LazyPattern3 lazyPattern; private LazyPattern3() { } /** * 假设: * 线程A获取到锁,并且创建对象:LazyPattern3 * 在线程A创建对象的过程中(未创建完) * 线程B判断第一个:lazyPattern == null,得到的结果为:False * 则:线程B获取到了线程A创建的不完整的LazyPattern3对象 * @return */ public static LazyPattern3 getInstance() { if (lazyPattern == null) { synchronized (LazyPattern3.class) { if (lazyPattern == null) { lazyPattern = new LazyPattern3(); } } } return lazyPattern; } public static void main(String[] args) { for (int i = 0; i < 5; i++) { Thread thread = new Thread(() -> { System.out.println(Thread.currentThread().getName() + " -> " + LazyPattern3.getInstance().hashCode()); }); thread.setName("Thread-" + i); thread.start(); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200813080126238.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter22#LazyPattern3 ## 懒汉模式 - 代码块双重判断锁 + volatile ```java /** * 懒汉模式 - 双重判断锁 + volatile * 关于为什么加上:volatile后,可以解决双重判断锁的问题 * 可以参考:https://www.cnblogs.com/jing-an-feng-shao/p/10275001.html */ public class LazyPattern4 { private static volatile LazyPattern4 lazyPattern; private LazyPattern4() { } public static LazyPattern4 getInstance() { if (lazyPattern == null) { synchronized (LazyPattern4.class) { if (lazyPattern == null) { lazyPattern = new LazyPattern4(); } } } return lazyPattern; } public static void main(String[] args) { for (int i = 0; i < 5; i++) { Thread thread = new Thread(() -> { System.out.println(Thread.currentThread().getName() + " -> " + LazyPattern4.getInstance().hashCode()); }); thread.setName("Thread-" + i); thread.start(); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200813080215478.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter22#LazyPattern4 ## 使用enum枚举类实现单例模式 在使用枚举类时,构造方法会被自动调用,可以通过这个特性实现单例模式。 ```java public class EnumSingleton { public enum InternalEnumSingleton { readAndReadObject; private ReadAndRead readAndRead; private InternalEnumSingleton() { System.out.println("创建EnumSingleton对象"); readAndRead = new ReadAndRead(); } public ReadAndRead getReadAndRead() { return readAndRead; } } public static ReadAndRead getReadAndRead() { return InternalEnumSingleton.readAndReadObject.getReadAndRead(); } public static void main(String[] args) { for (int i = 0; i < 10; i++) { Thread thread = new Thread(() -> { System.out.println(EnumSingleton.getReadAndRead().hashCode()); }); thread.start(); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200817075004370.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter22#EnumSingleton # Concurrent集合 | 接口 | 非线程安全 | 线程安全 | |--|--|--| | List | ArrayList | CopyOnWriteArrayList | | Map | HashMap | ConcurrentHashMap | | Set | HashSet / TreeSet | CopyOnWriteArraySet | | Queue | ArrayDeque / LinkedList | ArrayBlockingQueue / LinkedBlockingQueue | | Deque | ArrayDeque / LinkedList | LinkedBlockingDeque | - 使用**java.util.concurrent**包提供的线程安全的并发集合可以大大简化多线程编程 - 多线程同时读写并发集合是安全的 - 尽量使用Java标准库提供的并发集合,避免自己编写同步代码 # ExecutorService线程池 ## newCachedThreadPool 创建一个**可缓存线程池**,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程 ```java public class CachedThreadPoolTest { public static void main(String[] args) { ExecutorService cacheThreadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 100; i++) { cacheThreadPool.execute(new Thread(() -> { System.out.println("Thread name = " + Thread.currentThread().getName()); })); } cacheThreadPool.shutdown(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200818205330256.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter23#CachedThreadPoolTest ## newFixedThreadPool 创建一个**定长线程池**,可控制线程最大并发数,超出的线程会在队列中等待 ```java public class FixedThreadPool { public static void main(String[] args) { // 创建定长的线程池 ExecutorService executorService = Executors.newFixedThreadPool(5); // 遍历20次,线程数应在 ≤ 5 for (int i = 0; i < 20; i++) { executorService.execute(new Thread(() -> { System.out.println("Thread name = " + Thread.currentThread().getName()); })); } executorService.shutdown(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200818210026699.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter23#FixedThreadPoolTest ## newSingleThreadExecutor 创建一个**单线程化的线程池**,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行 ```java public class SingleThreadExecutorTest { public static void main(String[] args) { // 创建单线程线程池 ExecutorService executorService = Executors.newSingleThreadExecutor(); // 遍历10次,每次遍历的线程池应是同一个 for (int i = 0;i < 10; i++) { executorService.execute(new Thread(() -> { System.out.println("Thread name = " + Thread.currentThread().getName()); })); } executorService.shutdown(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200818210500211.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter23#SingleThreadExecutorTest ## newScheduledThreadPool 创建一个**定长线程池**,支持**定时及周期性**任务执行 ### 一次性任务,在指定延迟时间后执行一次(.schedule) ```java ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2); // 一次性任务,在指定延迟时间后执行一次 scheduledExecutorService.schedule(new Thread(() -> { System.out.println("schedule method -> " + Thread.currentThread().getName()); }), 1, TimeUnit.SECONDS); ``` ### 定时任务,每x秒执行一次(.scheduleAtFixedRate) ```java ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2); /** * initialDelay: 多少时间后执行 * period: 间隔时间 * 即:5秒后执行,每3秒执行一次 */ System.out.println("当前时间 -> " + new Date()); scheduledExecutorService.scheduleAtFixedRate(new Thread(() -> { System.out.println("scheduleAtFixedRate method -> " + Thread.currentThread().getName() + "; 目前时间为:" + new Date()); }), 5, 3, TimeUnit.SECONDS); ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200818212155182.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter23#ScheduledThreadPoolTest ### 定时任务,每x秒执行一次,线程任务执行时间大于x秒后的现象(.scheduleAtFixedRate) ```java ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2); /** * initialDelay: 多少时间后执行 * period: 间隔时间 * 即:5秒后执行,每3秒执行一次 * * 设定线程执行的任务所花费的时间大于3秒,那么线程的执行情况应该是怎么样的? */ System.out.println("当前时间 -> " + new Date()); scheduledExecutorService.scheduleAtFixedRate(new Thread(() -> { try { Thread.sleep(4000); System.out.println("scheduleAtFixedRate method -> " + Thread.currentThread().getName() + "; 目前时间为:" + new Date()); } catch (InterruptedException e) { e.printStackTrace(); } }), 5, 3, TimeUnit.SECONDS); ``` **结果是:在线程执行完成后,立刻执行下一个任务** ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200818212621519.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter23#ScheduledThreadPoolTest ### 定时任务,每x秒执行一次,线程任务执行时间大于x秒后的现象(.scheduleWithFixedDelay) ```java ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2); /** * initialDelay: 多少时间后执行 * period: 间隔时间 * 即:5秒后执行,每3秒执行一次 * * 设定线程执行的任务所花费的时间大于3秒,那么线程的执行情况应该是怎么样的? */ System.out.println("当前时间 -> " + new Date()); scheduledExecutorService.scheduleWithFixedDelay(new Thread(() -> { try { Thread.sleep(4000); System.out.println("scheduleAtFixedRate method -> " + Thread.currentThread().getName() + "; 目前时间为:" + new Date()); } catch (InterruptedException e) { e.printStackTrace(); } }), 5, 3, TimeUnit.SECONDS); ``` **结果是:在线程执行完成后,继续等待3秒后,再执行下一个任务** ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200818213016701.png#pic_center) > 代码:chapter23#ScheduledThreadPoolTest ## ExecutorService方法介绍 ### awaitTermination(long timeout, TimeUnit unit) 在所有任务执行了shundown() 或 timeout 或 interrupted()之前,都会一直阻塞着。 ```java public class AwaitTerminationTest { public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); // 线程任务在2s后执行完成 executorService.execute(new Thread(() -> { try { Thread.sleep(2000); System.out.println("Thread name = " + Thread.currentThread().getName() + "; Current time = " + new Date()); } catch (InterruptedException e) { e.printStackTrace(); } })); /** * 启动线程后,立刻执行shutdown() * 但是这时候,线程是还没有执行完成的 */ executorService.shutdown(); if (!executorService.awaitTermination(1, TimeUnit.SECONDS)) { System.out.println("Time1, awaitTermination = false, 线程未执行完!" ); } else { System.out.println("Time1, awaitTermination = true, 线程已执行完!" ); } // 主线程等待子线程执行完 Thread.sleep(2000); if (executorService.awaitTermination(1, TimeUnit.SECONDS)) { System.out.println("Time2, awaitTermination = true, 线程已执行完!" ); } else { System.out.println("Time2, awaitTermination = false, 线程未执行完!" ); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200818215359605.png#pic_center) > 代码:chapter24#AwaitTerminationTest ### invokeAll(Collection> tasks) 执行给定的任务,当所有任务完成时,返回其执行结果 ```java /** * 实现Callable接口,并且返回String类型的结果,返回结果具体情况具体分析 */ public class CallableClass implements Callable { String name; public CallableClass(String name) { this.name = name; } @Override public String call() throws Exception { return "Name = " + this.name; } } ``` ```java public class InvokeAllTest { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newSingleThreadExecutor(); List> tasks = new ArrayList<>(); tasks.add(new CallableClass("A")); tasks.add(new CallableClass("B")); List> futures = executorService.invokeAll(tasks); for (Future future : futures) { if (future.isDone() && !future.isCancelled()) { System.out.println(future.get()); } } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200818221859701.png#pic_center) > 代码:chapter24#InvokeAllTest ### invokeAll(Collection> tasks, long timeout, TimeUnit unit) 执行给定的任务,当所有任务完成或者超过了设定的时间时,返回其执行结果 ```java /** * 实现Callable接口,并且返回String类型的结果,返回结果具体情况具体分析 */ public class CallableClass implements Callable { String name; public CallableClass(String name) { this.name = name; } @Override public String call() throws Exception { String name = this.name; if (this.name.equals("B")) { Thread.sleep(2000); } return "Name = " + this.name; } } ``` ```java /** * name = A时,瞬间执行完任务 * name = B时,需要等待2s * 我们invokeAll设定的时间在1s * 所以,最终得到的结果只有name = A */ public class InvokeAllTest2 { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newFixedThreadPool(2); List> tasks = new ArrayList<>(); tasks.add(new CallableClass("A")); tasks.add(new CallableClass("B")); List> futures = executorService.invokeAll(tasks, 1, TimeUnit.SECONDS); for (Future future : futures) { if (future.isDone() && !future.isCancelled()) { System.out.println(future.get()); } } executorService.shutdown(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819101548818.png#pic_center) > 代码:chapter24#InvokeAllTest2 ### invokeAny(Collection> tasks) 执行给定的任务,返回其中一个最先成功完成的任务的结果 ```java /** * 实现Callable接口,并且返回String类型的结果,返回结果具体情况具体分析 */ public class CallableClass implements Callable { String name; public CallableClass(String name) { this.name = name; } @Override public String call() throws Exception { String name = this.name; if (this.name.equals("A")) { Thread.sleep(2000); } return "Name = " + this.name; } } ``` ```java /** * 因为name = A的任务需要等待2s的时间 * 所以B会先于A执行完 * 最终得到的结果是:Name = B */ public class InvokeAny { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newFixedThreadPool(2); List> tasks = new ArrayList<>(); tasks.add(new CallableClass("A")); tasks.add(new CallableClass("B")); tasks.add(new CallableClass("C")); String futureResult = executorService.invokeAny(tasks); System.out.println("Result = " + futureResult); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/202008200733072.png#pic_center) > 代码:chapter24#InvokeAnyTest ### invokeAny(Collection> tasks, long timeout, TimeUnit unit) 执行给定的任务,如果在超时之前完成任务,则返回任务中的结果。 任务超时的话,则会抛出Exception。 ```java /** * 实现Callable接口,并且返回String类型的结果,返回结果具体情况具体分析 */ public class CallableClass implements Callable { String name; public CallableClass(String name) { this.name = name; } @Override public String call() throws Exception { String name = this.name; if (this.name.equals("B")) { Thread.sleep(2000); } return "Name = " + this.name; } } ``` ```java /** * 执行name = B的任务需要2s的时间 * 我们期待在1s的时间拿到任务的结果 * 此时会抛出Exception */ public class InvokeAny2 { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newSingleThreadExecutor(); List> tasks = new ArrayList<>(); tasks.add(new CallableClass("B")); String futureResult = null; try { futureResult = executorService.invokeAny(tasks, 1, TimeUnit.SECONDS); } catch (TimeoutException e) { futureResult = "Exception"; } System.out.println(futureResult); executorService.shutdown(); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020082007384036.png#pic_center) > 代码:chapter24#InvokeAnyTest2 ### shutdown() 有序关闭之前触发的任务,不处理后续新加的任务。 ### isShutdown() 如果此执行程序已关闭,则返回true。 ```java /** * 执行任务,任务完成时间需要:2s * 在调用shutdown()前后,查看isShutdown()的值的前后变化 */ public class IsShutdownTest { public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.execute(new Thread(() -> { try { System.out.println("Sub thread is running.."); Thread.sleep(2000); System.out.println("Sub thread is down.."); } catch (InterruptedException e) { e.printStackTrace(); } })); Thread.sleep(1000); System.out.println("Before execute shutdown method, " + "isShutdown = " + executorService.isShutdown()); executorService.shutdown(); System.out.println("After execute shutdown method, " + "isShutdown = " + executorService.isShutdown()); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200820074715927.png#pic_center) > 代码:chapter24#IsShutdownTest ### isTerminated() isTerminated()需要所有的任务都结束了,才会返回true。 isShutdown()只要程序调用了shundown()后,就会返回true。 ```java /** * 执行任务,任务完成时间需要:2s * 在调用shutdown()前后,查看isTerminated()的值的前后变化 */ public class IsTerminatedTest { public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.execute(new Thread(() -> { try { System.out.println("Sub thread is running.."); Thread.sleep(2000); System.out.println("Sub thread is down.."); } catch (InterruptedException e) { e.printStackTrace(); } })); System.out.println("Before execute shutdown method, " + "isTerminated = " + executorService.isTerminated()); executorService.shutdown(); System.out.println("After execute shutdown method, but tasks still running, " + "isTerminated = " + executorService.isTerminated()); Thread.sleep(3000); System.out.println("After execute shutdown method and tasks is down, " + "isTerminated = " + executorService.isTerminated()); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200820075247654.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter24#IsTerminatedTest ### shutdownNow() 尝试停止所有正在执行的任务,中止正在等待的任务的处理,并返回正在等待执行的任务的列表 ```java /** * 给定一个单线程 * 提交5次执行的任务 * 任务中: * (1)如果 随机数 % 2 == 0,则线程进入睡眠5s * (2)如果 随机数 % 2 != 0,则线程立刻执行完毕 * 主线程中,睡眠1s后,查看待执行的线程数量 */ public class ShutdownNowTest { public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 0; i < 5; i++) { executorService.submit(new Thread(() -> { try { System.out.println(Thread.currentThread().getName() + " is running.."); int result = (int) (Math.random() * 10); System.out.println(Thread.currentThread().getName() + " result = " + result); if (result % 2 == 0) { System.out.println(Thread.currentThread().getName() + " is sleeping.."); Thread.sleep(5000); } System.out.println(Thread.currentThread().getName() + " is down.."); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName() + " throws exception"); } })); } Thread.sleep(1000); List runnables = executorService.shutdownNow(); System.out.println("Waiting list size = " + runnables.size()); } } ``` 总共有5个任务要执行,前2个任务都是瞬间完成了,第3个任务进入了睡眠,第4、5个任务处于待执行的阶段。 所以结果是:2个任务执行完成,1个任务进入睡眠,2个任务待执行。 在执行了shutdownNow()后,进入睡眠的线程任务会被中断,并抛出异常 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200820081334938.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter24#ShutdownNowTest ### submit(Callable task) 提交待执行的任务,并且得到任务返回的结果。 ```java public class SubmitTest { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); // submit(Callable task) for (int i = 0; i < 5; i++) { Future future = executorService.submit(new CallableClass("A")); System.out.println(future.get()); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200820085226375.png#pic_center) > 代码:chapter24#SubmitTest ### submit(Runnable task) 提交一个Runnable任务用于执行,并返回一个代表该任务的Future。(不知道这个有什么作用) **future.get() = null** ```java public class SubmitTest2 { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); // submit(Runnable task) for (int i = 0; i < 5; i++) { Future future = executorService.submit(new Runnable() { @Override public void run() { System.out.println("TEST"); } }); System.out.println(future); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200820085354817.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter24#SubmitTest2 ### submit(Runnable task, T result) 同上,但是可以自己指定返回的结果是什么。 **future.get() = result** ```java public class SubmitTest3 { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); // submit(Runnable task, T result) for (int i = 0; i < 5; i++) { Future future = executorService.submit(new Runnable() { @Override public void run() { System.out.println("TEST"); } }, "I'm Result"); System.out.println(future.get()); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200820085559581.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTkxNTMxNA==,size_16,color_FFFFFF,t_70#pic_center) > 代码:chapter24#SubmitTest3 # Future Future表示异步执行结果。Future提供了一些方法,以用于查看任务是否执行完成。 - 在任务完成后,可以通过get()的方式得到返回的结果 - 可以用cancel()的方式取消任务 - 任务一旦完成后,将不能够再被取消掉 ## get() 将会阻塞线程,直到拿到返回值或者抛出异常 ## get(long timeout, TimeUnit unit) 在指定的时间内拿不到返回值,则抛出java.util.concurrent.TimeoutException异常 ```java /** * 在符合this.number % 2 == 0条件下 * 线程将会睡眠5s */ public class CallableTestClass implements Callable { int number; public CallableTestClass(int number) { this.number = number; } @Override public String call() throws Exception { if (this.number % 2 == 0) { Thread.sleep(5000); } return "Current thread name = " + Thread.currentThread().getName(); } } ``` ```java /** * 设定get(long timeout, TimeUnit unit)在1s中获取任务返回值,否则抛出异常 */ public class FutureGetTest { public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException { ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 1; i <= 2; i++) { CallableTestClass callableTestClass = new CallableTestClass(i); Future future = executorService.submit(callableTestClass); System.out.println("Method get(long timeout, TimeUnit unit) -> " + future.get(1, TimeUnit.SECONDS)); System.out.println("Method get() -> " + future.get()); } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200821073250689.png#pic_center) [关于Future.cancel(false)](https://blog.csdn.net/StefanTimber/article/details/73823689) > 代码:chapter25#FutureGetTest # 参考资料 书:《Java多线程编程核心技术》--- 高洪岩 [Interface ExecutorService](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html) [廖雪峰的多线程学习资料](https://www.liaoxuefeng.com/wiki/1252599548343744/1255943750561472) [Java 四种线程池](https://www.cnblogs.com/zhujiabin/p/5404771.html) [Java Platform SE 7](https://docs.oracle.com/javase/7/docs/api/index.html) [Class CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) [CompletableFuture](https://www.jianshu.com/p/b3c4dd85901e) [Java Fork/Join 框架](https://www.cnblogs.com/cjsblog/p/9078341.html) # 代码 https://gitee.com/Protector_hui/concurrency-study.git