===================== Callable ===============================
创建线程多种方式
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
- 线程池方式
Runnable接口和Callable接口区别
- 是否有返回值
- 是否抛出异常
- 实现名称不同,一个是run 一个是call
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
Callable创建线程
Runnable接口有实现类FutureTask
FutureTask构造可以传递Callable
package com.example.juclearn.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class MyThread1 implements Runnable {
@Override
public void run() {
System.out.println("实现Runnable接口创建线程。。。");
}
}
class MyThread2 implements Callable {
@Override
public Integer call() throws Exception {
return 200;
}
}
public class CallableDemo {
public static void main(String[] args) {
new Thread(new MyThread1(),"A").start();
// 类实现
FutureTask futureTask1 = new FutureTask<>(new MyThread2());
// lambda实现
FutureTask<Integer> futureTask2 = new FutureTask<>(() -> {
return 1024;
});
new Thread(futureTask1,"B").start();
// 任务是否完成 完成之后才会得到结果
while (!futureTask1.isDone()) {
System.out.println("wait..");
}
try {
System.out.println(futureTask1.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
======================= JUC强大的辅助类 ==== ====================
减少计数CountDownLatch
实现功能,教室中6个人都离开后班长锁门
package com.example.juclearn.juchelpclass;
import java.util.concurrent.CountDownLatch;
/**
* 教室中的6个人都离开时,班长锁门
*/
public class CountDownLatchDemo {
public static void main(String[] args) {
// 共有6个人,创建对象的参数的阈值为6
CountDownLatch countDownLatch = new CountDownLatch(6);
// 6个人创建6个线程
for (int i = 0; i < 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName() + " 离开了教室。。。");
// 每离开一个人 数量减一
countDownLatch.countDown();
},String.valueOf(i+1)).start();
}
try {
// 当数值没有达到0时,一直等待
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("班长锁门。。。。");
}
}
循环栅栏CyclicBarrier
实现功能:集齐7个龙珠可以召唤神龙
package com.example.juclearn.juchelpclass;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* 集齐7个龙珠可以召唤神龙
*/
public class CyclicBarrierDemo {
// 设置阈值
public static final int NUMBER = 7;
public static void main(String[] args) {
CyclicBarrier cyclicBarrier =
new CyclicBarrier(NUMBER,()->{
System.out.println("----集齐7颗龙珠 召唤神龙-----");
});
for (int i = 0; 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+1)).start();
}
}
}
信号灯Semaphore
实现功能:6辆车 3个停车位
package com.example.juclearn.juchelpclass;
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* 6辆车 3个车位
*/
public class SemaphoreDemo {
public static void main(String[] args) {
// 参数为许可数量 这里的停车位数量
Semaphore semaphore = new Semaphore(3);
// 设置6辆车
for (int i = 0; i < 6; i++) {
new Thread(() -> {
try {
// 抢占
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " 抢到了车位。。。");
// 停留时间
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
System.out.println(Thread.currentThread().getName() + "---离开了车位---");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放
semaphore.release();
}
}, String.valueOf(i + 1)).start();
}
}
}
====================== 读写锁 ==============================
定义:一个资源可以被多个读线程访问,或者可以被一个写线程访问,但是不能同时存在读写线程,读写互斥,读读共享
- 无锁情况:多线程抢夺资源,较乱
- 添加锁:synchronized和lock,独占锁,每次只能一个线程操作
- 读写锁:ReentrantReadWriteLock,读读时可以共享,提升性能。但是会造成锁饥饿一直读没有写操作;读时不能写,只有写操作时可以读。
降级锁
package com.example.juclearn.readwritelock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 锁降级顺序
*/
public class LockDecr {
public static void main(String[] args) {
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 获取写锁
readWriteLock.writeLock().lock();
// 获取读锁
readWriteLock.readLock().lock();
// 释放写锁
readWriteLock.writeLock().unlock();
// 释放读锁
readWriteLock.readLock().unlock();
}
}
=========================== 阻塞队列 ===========================
介绍
- 当队列为空,从队列中获取元素的操作将会被阻塞
- 当队列已满,向队列中添加元素的操作将会被阻塞
- 试图从空的队列中获取元素的线程将会被阻塞,直到其他线程往空的队列插入新的元素
- 试图向已满的队列中添加元素将会被阻塞,直到其他线程从队列中移除一个或者多个元素,是队列变得空闲
分类
- ArrayBlockingQueue:数组结构组成的有界阻塞队列,用于生产者消费者模式
- LinkedBlockingQueue:链表结构组成的有界阻塞队列,用于生产者消费者模式
- DelayQueue:使用优先级队列实现的延迟无界阻塞队列
- PriorityBlockingQueue:支持优先级排序的无阻塞队列
- SynchronousQueue
- LinkedTransferQueue
- LinkedBlockingDeque
package com.example.juclearn.blockingqueue;
import java.util.concurrent.ArrayBlockingQueue;
public class ArrayBlockingQueueDemo {
public static void main(String[] args) {
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<String>(3);
arrayBlockingQueue.add("1");
arrayBlockingQueue.add("2");
arrayBlockingQueue.add("3");
// add方法添加元素多余容量时抛出异常 Exception in thread "main" java.lang.IllegalStateException: Queue full
// arrayBlockingQueue.add("4");
arrayBlockingQueue.remove();
arrayBlockingQueue.remove();
arrayBlockingQueue.remove();
// remove方法移除元素多余队列中元素个数时会抛出异常 Exception in thread "main" java.util.NoSuchElementException
// arrayBlockingQueue.remove();
// 返回队列首元素 如果没有元素则抛出异常 Exception in thread "main" java.util.NoSuchElementException
System.out.println(arrayBlockingQueue.element());
}
}
package com.example.juclearn.blockingqueue;
import java.util.concurrent.ArrayBlockingQueue;
public class ArrayBlockingQueueDemo1 {
public static void main(String[] args) {
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<String>(3);
// 插入成功返回true
System.out.println(arrayBlockingQueue.offer("1"));
System.out.println(arrayBlockingQueue.offer("2"));
System.out.println(arrayBlockingQueue.offer("3"));
// 插入失败返回false 没有抛出异常
System.out.println(arrayBlockingQueue.offer("4"));
//移除成功返回移除的值
System.out.println(arrayBlockingQueue.poll());
System.out.println(arrayBlockingQueue.poll());
System.out.println(arrayBlockingQueue.poll());
// 队列为空时移除的值为null
System.out.println(arrayBlockingQueue.poll());
// 返回队列首元素 如果没有元素则返回null
System.out.println(arrayBlockingQueue.peek());
}
}
package com.example.juclearn.blockingqueue;
import java.util.concurrent.ArrayBlockingQueue;
public class ArrayBlockingQueueDemo2 {
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<String>(3);
// 插入成功返回true
arrayBlockingQueue.put("1");
arrayBlockingQueue.put("2");
arrayBlockingQueue.put("3");
// 无法插入处于阻塞状态
// arrayBlockingQueue.put("4");
//移除成功返回移除的值
System.out.println(arrayBlockingQueue.take());
System.out.println(arrayBlockingQueue.take());
System.out.println(arrayBlockingQueue.take());
// 队列为空时移除的处于阻塞状态
System.out.println(arrayBlockingQueue.take());
}
}
package com.example.juclearn.blockingqueue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
public class ArrayBlockingQueueDemo3 {
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<String>(3);
// 插入成功返回true
System.out.println(arrayBlockingQueue.offer("1",3, TimeUnit.SECONDS));
System.out.println(arrayBlockingQueue.offer("2",3, TimeUnit.SECONDS));
System.out.println(arrayBlockingQueue.offer("3",3, TimeUnit.SECONDS));
// 插入失败返回false 阻塞时间设置为3s
System.out.println(arrayBlockingQueue.offer("4",3, TimeUnit.SECONDS));
//移除成功返回移除的值
System.out.println(arrayBlockingQueue.poll(3, TimeUnit.SECONDS));
System.out.println(arrayBlockingQueue.poll(3, TimeUnit.SECONDS));
System.out.println(arrayBlockingQueue.poll(3, TimeUnit.SECONDS));
// 队列为空时移除的值为null,阻塞时间设置为3s
System.out.println(arrayBlockingQueue.poll(3, TimeUnit.SECONDS));
}
}
=========================== 线程池 ===============================
分类
- 一池N线程
- 一池一线程
- 一池可扩容线程
一池一线程 无论多少个人办理业务,都只有一个线程处理
package com.example.juclearn.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 一池一线程
ExecutorService threadPool1 = Executors.newSingleThreadExecutor();//相当于银行只有一个窗口
// 一池N线程 参数为N的数量
ExecutorService threadPool2 = Executors.newFixedThreadPool(5);//相当于银行有五个窗口
// 一池可扩容线程
ExecutorService threadPool3 = Executors.newCachedThreadPool();//相当于银行随机开放窗口
try{
for (int i = 0; i < 10; i++) {
threadPool1.execute(()->{
System.out.println(Thread.currentThread().getName()+"办理业务");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
threadPool1.shutdown();
}
}
}
最多有5个线程处理业务
package com.example.juclearn.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 一池一线程
ExecutorService threadPool1 = Executors.newSingleThreadExecutor();//相当于银行只有一个窗口
// 一池N线程 参数为N的数量
ExecutorService threadPool2 = Executors.newFixedThreadPool(5);//相当于银行有五个窗口
// 一池可扩容线程
ExecutorService threadPool3 = Executors.newCachedThreadPool();//相当于银行随机开放窗口
try{
for (int i = 0; i < 10; i++) {
threadPool2.execute(()->{
System.out.println(Thread.currentThread().getName()+"办理业务");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
threadPool2.shutdown();
}
}
}
package com.example.juclearn.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 一池一线程
ExecutorService threadPool1 = Executors.newSingleThreadExecutor();//相当于银行只有一个窗口
// 一池N线程 参数为N的数量
ExecutorService threadPool2 = Executors.newFixedThreadPool(5);//相当于银行有五个窗口
// 一池可扩容线程
ExecutorService threadPool3 = Executors.newCachedThreadPool();//相当于银行随机开放窗口
try{
for (int i = 0; i < 10; i++) {
threadPool3.execute(()->{
System.out.println(Thread.currentThread().getName()+"办理业务");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
threadPool3.shutdown();
}
}
}
参数解释
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
底层工作流程
拒绝策略
自定义线程池
线程池不允许使用Excutors去创建,而是要通过ThreadPoolExecutor的方式创建,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
Executors返回线程池对象的弊端如下:
- FixedThreadPool 和SingleThreadPool允许的请求队列长度是Integer.MAX_VALUE,可能堆积大量请求,导致OOM
- CachedThreadPool允许创建线程的数量是Integer.MAX_VALUE,导致OOM
package com.example.juclearn.threadpool;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class UserDefineThreadPool {
public static void main(String[] args) {
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
2,
5,
2,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
try{
for (int i = 0; i < 10; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"办理业务");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
threadPool.shutdown();
}
}
}
每次执行结果都不同。
========================= ForkJoin 框架 ======================
简介
Fork/Join 可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果,并进行输出。
Fork:把一个复杂的任务进行拆分,大事化小
Join:将分拆任务的结果进行合并
实例
实现1+2+3+4+…+100,我们将差值不超过10的部分进行相加,最后合并
package com.example.juclearn.forkjoin;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
class MyTask extends RecursiveTask<Integer> {
// 计算差值不超过10的和
private static final int CHA = 10;
// 拆分开始值
private int start;
// 拆分结束值
private int end;
// 得到的结果
private int result;
public MyTask(int start, int end) {
this.start = start;
this.end = end;
}
/**
* 拆分合并过程
* @return
*/
@Override
protected Integer compute() {
MyTask myTask = new MyTask(start,end);
// 差值是否小于10
if (end - start <=10) {
// 相加
for (int i = start; i <= end ; i++) {
result += i;
}
}else {
// 计算中间值
int middle = (start + end)/2;
// 任务拆分 左边
MyTask myTask1 = new MyTask(start, middle);
// 任务拆分 右边
MyTask myTask2 = new MyTask(middle + 1, end);
// 调用拆分方法
myTask1.fork();
myTask2.fork();
// 拆分后的任务合并
result = myTask1.join() + myTask2.join();
}
return result;
}
}
public class ForkJoinDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyTask myTask = new MyTask(0, 100);
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask<Integer> submit = forkJoinPool.submit(myTask);
Integer result = submit.get();
System.out.println(result);
forkJoinPool.shutdown();
}
}
========================= JUC异步回调 ============================
异步:当我去教室找人,发现不在时,转告其他同学如果他回来的话告诉我,我继续忙我其他的事情
package com.example.juclearn.completablefuture;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureDemo {
public static void main(String[] args) {
// 异步回调 没有返回值
CompletableFuture<Void> completableFuture1 = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName() + " completableFuture1");
});
try {
completableFuture1.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
// 异步回调 有返回值
CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " completableFuture2");
return 1024;
});
/**
* 当完成时输出内容
*/
completableFuture2.whenComplete((t,u)->{
// 方法返回值
System.out.println("t=" + t);
// 异常情况,没有返回null
System.out.println("u=" + u);
});
}
}