JUC内容概述

复习概念

Sleep和Wait的区别

  1. Sleep是Thread的静态方法,wait是Object的方法,任何对象实例都可以使用
  2. sleep不会释放锁,他也不需要占用锁,暂停。wait会释放锁,但是调用他的前提是线程占有锁
  3. 他们都可以被Interrupted方法中断。在哪里停,在哪里起

并发并行

并发:同一时刻,多个线程访问同一资源

并行:多项工作一起执行,之后汇总

线程的状态

Thread.status

管程

monitor监视器 所说的锁

是一种同步机制,保证同一时间,只有一个线程 访问被保护的数据或者代码

用户线程和守护线程

用户线程:自定义线程,平时用到的具体逻辑

守护线程:垃圾回收线程

主线程已经结束了,用户线程还在运行,jvm存活、

如果程序中没有用户线程了,守护线程也会结束,在执行start之前设置是否是守护线程。

卖票程序:

package com.policy.thread;class Ticket{private int ticket =30;public synchronized void sale(){if(ticket>0){System.out.println(Thread.currentThread().getName()+"卖出:"+(ticket--)+"剩余:"+ticket);}}
}public class SaleTicket {public static void main(String[] args) {Ticket ticket = new Ticket();new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 40; i++) {ticket.sale();}}},"a").start();new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 40; i++) {ticket.sale();}}},"b").start();new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 40; i++) {ticket.sale();}}},"c").start();}}

可重入锁

Lock.lock()

Lock.unlock()

lock不是java内置的,synchronized是java关键字

sync不需要手动释放锁,lock上锁之后需要手动释放锁

package com.policy.thread;import java.util.concurrent.locks.ReentrantLock;class LTicket{private int num=30;//创建可重入锁private final ReentrantLock lock = new ReentrantLock();//卖票方法public void sale(){//上锁lock.lock();try {if(num>0){System.out.println(Thread.currentThread().getName()+"卖出"+(num--)+"剩余"+num);}} catch (Exception e) {throw new RuntimeException(e);} finally {//解锁lock.unlock();}}
}public class LTicketSale {public static void main(String[] args) {LTicket lTicket = new LTicket();//创建线程 表达式new Thread(()->{for (int i = 0; i < 40; i++) {lTicket.sale();}},"a").start();new Thread(()->{for (int i = 0; i < 40; i++) {lTicket.sale();}},"b").start();new Thread(()->{for (int i = 0; i < 40; i++) {lTicket.sale();}},"c").start();}}

Lock 与Sync总结

1、Lock是一个接口,sync是java的关键字,是一种内置的实现语言

2、当sync发生异常时,会自动释放占有的锁,因此不会导致死锁的发生;

Lock在发生异常时,如果没有主动通过unLock释放锁,则很可能会造成死锁现象,因此在Finally中释放锁是很必要的。

3、Lock会让等待锁的线程响应中断,而sync却不会中断等待线程,使用sync会一直等待下去,不能够响应中断。

4、通过lock可以知道有没有成功获取锁,而Sync却无法办到。

5、Lock可以提高多个线程读操作的效率。

线程通信

第一步:创建资源类,在资源类中创建属性和方法

第二步:方法中

判断、干活、通知

第三步:创建多个线程,调用资源类的操作方法

第四步:防止虚假唤醒问题

package com.policy.thread.Thread202308;
class Share{//线程等待和唤醒private int num=0;public synchronized void incr() throws InterruptedException {//加一操作if(num!=0){//不等于0说明不需要加一 等待this.wait();}//加一num++;System.out.println(Thread.currentThread().getName()+"::"+num);//唤醒其他线程 可以减一了this.notifyAll();}public synchronized void decr() throws InterruptedException {if(num!=1){//等待this.wait();}//减一num--;System.out.println(Thread.currentThread().getName()+"::"+num);this.notifyAll();}
}public class ThreadDemo01 {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) {throw new RuntimeException(e);}}},"aa").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {share.decr();} catch (InterruptedException e) {throw new RuntimeException(e);}}},"bb").start();}}

此方法 如果多了线程之后 增加CCDD线程执行操作会有虚假唤醒的问题,问题的原因是出现在判断条件中

A释放之后 BCD都有机会抢到,C抢到了C也会等待,然后再去让其他线程抢,继续唤醒A线程,WAIT有一个问题,就是在哪等待,唤醒之后在哪执行,那么会执行if下面的语句,第二次执行A可能会继续执行+1

解决:把判断放到while循环中,无论什么时候唤醒,都会在执行循环的判断条件。

package com.policy.thread.Thread202308;
class Share{//线程等待和唤醒private int num=0;public synchronized void incr() throws InterruptedException {//加一操作while(num!=0){//不等于0说明不需要加一 等待this.wait();}//加一num++;System.out.println(Thread.currentThread().getName()+"::"+num);//唤醒其他线程 可以减一了this.notifyAll();}public synchronized void decr() throws InterruptedException {while(num!=1){//等待this.wait();}//减一num--;System.out.println(Thread.currentThread().getName()+"::"+num);this.notifyAll();}
}public class ThreadDemo01 {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) {throw new RuntimeException(e);}}},"aa").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {share.decr();} catch (InterruptedException e) {throw new RuntimeException(e);}}},"bb").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {share.incr();} catch (InterruptedException e) {throw new RuntimeException(e);}}},"cc").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {share.decr();} catch (InterruptedException e) {throw new RuntimeException(e);}}},"dd").start();}}

Lock实现上锁和线程通信

lock.lock();上锁

lock.unlock();解锁

condition.await();等待

condition.signalAll();唤醒其他线程

package com.policy.thread.Thread202308;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;class Share02{//创建锁private Lock    =new ReentrantLock();Condition condition = lock.newCondition();private int num = 0;public void incr() throws InterruptedException {//上锁lock.lock();try {while (num!=0){//通信等待condition.await();}//干活num++;System.out.println(Thread.currentThread().getName()+"::"+num);condition.signalAll();} finally {//解锁lock.unlock();}//判断 干活 通信}public void decr() throws InterruptedException {//上锁lock.lock();try {while (num!=1){//通信等待condition.await();}//干活num--;System.out.println(Thread.currentThread().getName()+"::"+num);condition.signalAll();} finally {lock.unlock();}//判断 干活 通信}
}public class ThradDemo02 {public static void main(String[] args) {Share02 share02 = new Share02();new Thread(()->{try {for (int i = 0; i < 10; i++) {share02.incr();}} catch (InterruptedException e) {throw new RuntimeException(e);}},"A").start();new Thread(()->{try {share02.decr();} catch (InterruptedException e) {throw new RuntimeException(e);}},"B").start();new Thread(()->{try {for (int i = 0; i < 10; i++) {share02.decr();}} catch (InterruptedException e) {throw new RuntimeException(e);}},"C").start();new Thread(()->{try {for (int i = 0; i < 10; i++) {share02.decr();}} catch (InterruptedException e) {throw new RuntimeException(e);}},"D").start();}
}

线程定制化通信

以上不管使用那种方式上锁或者进行通信 但是都不能将数据进行有顺序的固定化的通信

例如 指定三个线程,按照要求执行

AA打印5次 BB打印10次 CC打印15次

进行十轮

package com.policy.thread.Thread202308;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;class ShareResource{private int falg =1;//1表示A的 2-B 3C//创建锁private Lock lock =new ReentrantLock();//创建三个conditionprivate Condition c1= lock.newCondition();private Condition c2 = lock.newCondition();private Condition c3=lock.newCondition();public void print5(int loop) throws InterruptedException {lock.lock();try {while (falg!=1){//等待 不打印Ac1.await();}for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName()+"::"+i+"当前是第轮:"+loop);}//通知falg=2;//修改flag标示位的值c2.signal();//此时在A线程中 唤醒的是C2} finally {lock.unlock();}}public void print10(int loop) throws InterruptedException {lock.lock();//上锁try {//等待while (falg!=2){c2.await();}//干活for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+"::"+i+"当前是第轮:"+loop);}//通知falg=3;c3.signal();} finally {lock.unlock();}}public void print15(int loop) throws InterruptedException {lock.lock();//上锁try {//等待while (falg!=3){c3.await();}//干活for (int i = 0; i < 15; i++) {System.out.println(Thread.currentThread().getName()+"::"+i+"当前是第轮:"+loop);}//通知falg=1;c1.signal();} finally {lock.unlock();}}
}public class ThreadDemo3 {public static void main(String[] args) {ShareResource shareResource = new ShareResource();new Thread(()->{for (int i = 0; i < 10; i++) {try {shareResource.print5(i);} catch (InterruptedException e) {throw new RuntimeException(e);}}},"A").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {shareResource.print10(i);} catch (InterruptedException e) {throw new RuntimeException(e);}}},"B").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {shareResource.print15(i);} catch (InterruptedException e) {throw new RuntimeException(e);}}},"C").start();}
}

集合的线程安全

集合不安全的情况

List线程不安全的例子

在一边向list中add 一边需要输出list时 有可能会报错:并发修改异常

Exception in thread "2" Exception in thread "5" Exception in thread "1" Exception in thread "4" java.util.ConcurrentModificationException

package com.policy.thread.Thread202308;import java.util.ArrayList;
import java.util.List;
import java.util.UUID;public class ThreadDemo04 {public static void main(String[] args) {List<String> list = new ArrayList<>();for (int i = 0; i < 10; i++) {new Thread(()->{list.add(UUID.randomUUID().toString().substring(0,8));System.out.println(list);},String.valueOf(i)).start();}}
}

  

解决方案:

list之所以会报错并发修改异常 原因是list并没有加上synchronized关键字修饰

1、Vcetor 少用

Vector 的方法上 都加上了synchronized

package com.policy.thread.Thread202308;import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.Vector;public class ThreadDemo04 {public static void main(String[] args) {List<String> list = new Vector<>();for (int i = 0; i < 10; i++) {new Thread(()->{list.add(UUID.randomUUID().toString().substring(0,8));System.out.println(list);},String.valueOf(i)).start();}}
}

2、Collections

List<String> list = Collections.synchronizedList(new ArrayList<>());

通过调用Collections中的synchronized方法 即可将new出的List变成线程安全的

一般也少用

3、CopyOnWriteArrayList

List<String> list =new CopyOnWriteArrayList<>();

写时复制技术

可以并发的读取list的内容,但是需要向list写入的时候,需要复制一份写入新内容,然后将两份合并起来,读取合并后的新内容。兼顾了并发读 和写的操作

HashSet不安全的情况

Set<String> set =new HashSet<>();
for (int i = 0; i < 30; i++) {new Thread(()->{set.add(UUID.randomUUID().toString().substring(0,8));System.out.println(set);},String.valueOf(i)).start();
}

Exception in thread "5" Exception in thread "17" Exception in thread "21" Exception in thread "23" Exception in thread "24" Exception in thread "28" java.util.ConcurrentModificationException

解决方法

CopyOnWriteArraySet

Set<String> set = new CopyOnWriteArraySet<>();

HashMap不安全的情况

Map<String,String> map =new HashMap<>();
for (int i = 0; i < 30; i++) {new Thread(()->{map.put(UUID.randomUUID().toString().substring(0,8),"1111");System.out.println(map);},String.valueOf(i)).start();
}

解决方案

Map<String,String > map =new ConcurrentHashMap<>();

多线程锁

synchronized实现同步方法的基础:java每个对象都可以作为锁,具体的表现有三种形式。

对于普通的同步方法,锁的是当前实例的对象

对于静态同步方法,锁的是当前类的Class

对于同步方法块,锁的是Synchronized括号里面的配置对象

公平锁和非公平锁

非公平锁:线程会饿死,但是执行效率高

公平锁:阳光普照,效率相对低

可重入锁

synchronized 和Lock都是可重入锁

syn是一种隐式的可重入锁,Lock是显示的可重入锁 可重入锁也叫递归锁

死锁

两个或者两个以上的进程在执行过程中,因为争夺资源而造成的一种互相等待的现象,如果没有外力干涉他们就无法执行下去的现象、

产生死锁的原因:

1、系统资源不足

2、进程运行的推进顺序不合适

3、资源分配不当

package com.policy.thread.Thread202308;import java.sql.Time;
import java.util.concurrent.TimeUnit;public class DeadLock {//创建两个对象static Object a = new Object();static Object b = new Object();public static void main(String[] args) {new Thread(()->{synchronized (a){System.out.println(Thread.currentThread().getName()+"持有A,试图获取B");try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (b){System.out.println(Thread.currentThread().getName()+"获取B");}}},"A").start();new Thread(()->{synchronized (b){System.out.println(Thread.currentThread().getName()+"持有B,试图获取A");try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (a){System.out.println(Thread.currentThread().getName()+"获取A");}}},"B").start();}
}

验证死锁

1、jps 类似于:linux ps -ef

2、jstack :jvm自带的堆栈跟踪工具

Callable接口

Callable接口可以提供返回值

Runnable和Callable 区别

run call

无返回值 有返回值

无异常抛出 有异常抛出

package com.policy.thread.Thread202308.callable;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;//实现runnable接口
class Mythread1 implements Runnable{@Overridepublic void run() {}
}class Mythread2 implements Callable{@Overridepublic Object call() throws Exception {return 200;}
}public class Demo1 {public static void main(String[] args) throws ExecutionException, InterruptedException {//调用runnable接口Mythread1 mythread1 = new Mythread1();Thread thread = new Thread(mythread1);thread.setName("a");thread.start();//调用callable//FutureTask是runnable的实现接口//future 构造方法可以传递CallableFutureTask<Integer> futureTask = new FutureTask<>(new Mythread2());//以上的代码 可以用lambda表达式做简化FutureTask<Integer> futureTask1 = new FutureTask<>(()->{return 1024;});//FutureTask 原理 为什么叫未来任务new Thread(futureTask1).start();System.out.println(futureTask1.get());}}

Future优缺点

优点:future结合线程池异步多任务配合,能显著的提高程序的执行效率。

package com.policy.thread.JUC;import java.util.concurrent.*;public class FutureThreadPoolDemo {public static void main(String[] args) throws InterruptedException, ExecutionException {long start = System.currentTimeMillis();//线程池ExecutorService threadPool = Executors.newFixedThreadPool(3);//开启多个异步任务 处理FutureTask<String> task1 = new FutureTask<>(() -> {TimeUnit.MILLISECONDS.sleep(500);return "task1 over";});FutureTask<String> task2 = new FutureTask<>(() -> {TimeUnit.MILLISECONDS.sleep(300);return "task2 over";});FutureTask<String> task3 = new FutureTask<>(() -> {TimeUnit.MILLISECONDS.sleep(300);return "task3 over";});threadPool.submit(task1);threadPool.submit(task2);threadPool.submit(task3);//获取结果System.out.println(task1.get());System.out.println(task2.get());System.out.println(task3.get());threadPool.shutdown();long end = System.currentTimeMillis();System.out.println(end-start+"毫秒");System.out.println(Thread.currentThread().getName()+"执行结束");}private static void m1() throws InterruptedException {long start = System.currentTimeMillis();TimeUnit.MILLISECONDS.sleep(500);TimeUnit.MILLISECONDS.sleep(300);TimeUnit.MILLISECONDS.sleep(300);long end = System.currentTimeMillis();System.out.println(end-start+"毫秒");System.out.println(Thread.currentThread().getName()+"执行结束");}
}

缺点 FutureTask的缺点、

get方法会阻塞:

package com.policy.thread.JUC;import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;public class FutureAPIDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {FutureTask<String> stringFutureTask = new FutureTask<>(() -> {System.out.println(Thread.currentThread().getName() + "come in!");TimeUnit.SECONDS.sleep(5);return "task over";});Thread thread = new Thread(stringFutureTask);thread.start();System.out.println(stringFutureTask.get());//非要等到结果 才会执行//由于会在上面get不到结果 需要等五秒之后才能get到  所以 线程会阻塞五秒 才能执行下面的输出System.out.println("main over");}
}

1、get容易阻塞,一般放到最后才执行

2、如果不愿放到最后,我希望过时不候,可以自动离开

System.out.println(stringFutureTask.get(3,TimeUnit.SECONDS));

最后超过时间会抛出异常

JUC的辅助类

1、减少计数的CountDownLatch

CountDownLatch主要有两个方法,当一个或者多个线程调用 await方法时,这个线程会阻塞。

调用CountDown方法会将计数器减一。当计数器变为0时,因await方法阻塞的线程会被唤醒,继续执行。

2、循环栅栏CyclicBarrier

3、信号灯Semaphore

读写锁

悲观锁

不支持并发操作

乐观锁

表锁

操作表中的一行的记录或者数据 整张表都上锁

行锁

操作表中第一行的数据,只对第一行上锁,其他线程可以操作其他行的数据

读锁

共享锁

写锁

独占锁

读写锁都有可能发生死锁的状况

读锁发生死锁的状况

读写锁的例子,如果不加上读写锁,那么在还没有写完时就会执行读取的操作,

加锁之后,写完才可以读,并且可以看到结果中写操作是独占的,读操作是共享的。

读写锁:一个资源可以被多个读操作线程访问,一个资源只能被一个写操作线程访问,一个资源不能同时存在读写线程访问,读写互斥,写写互斥,读读共享。

无锁时,多个线程共 全的情况发生。

添加锁synchronized或者Lock这样就变成了线程独占的了,资源不共享,变成单线程的了

添加读写锁ReentrantReadWriteLock:相较与上面的锁,读读操作变成了共享的了,提升性能,多线程可共同操作(读)一个资源

缺点:造成 锁饥饿,一直读没有写操作、 读的时候不能写,读完了才可以写,写的时候可以读。=会造成锁降级的过程

锁降级

写入锁降级为读锁的过程

jdk8 中锁降级的过程:

阻塞队列

BlockingQueue阻塞队列

当队列为空的时候,从对列中获取元素,只能阻塞

当队列是满的时候,向队列中添加元素,阻塞

好处是,一系列的判断是否为空,满的操作,都是自动完成的。我们不需要关心什么时候需要挂起线程,什么时候需要唤醒线程。

这些都是阻塞队列封装好的。

阻塞队列的架构

ArrayBlockingQueue:基于数组实现的阻塞队列,内部维护了一个定长的数组,以便缓存队列的数据对象。

LinkedBlockingQueue:由链表组成的阻塞队列

DelayQueue:使用优先级队列 实现的延迟无界的队列。

PriorityBlockQueue:支持优先级排序的队列

SynchronousQueue:无缓冲的阻塞队列,不存储元素的的阻塞队列,只存单个元素‘

LinkedTransferQueue:链表组成的无界阻塞队列

LinkedBlockDeque:有链表组成的双向阻塞队列

add、remove这一组的话,在长度范围内正常操作,add会返回true或者false 超过之后会抛出异常

offer和poll offer满了之后添加不会抛异常,会返回false 队列空了之后,执行poll,会进行返回null 不会抛异常

put 当队列满了之后会一直阻塞在那里,take也是,队列空了之后不会结束也不会完成 会停留在那里

第四组的offer poll设置超时时间,在时间范围内阻塞 超时就会退出 offer会返回false

ThreadPool线程池

一种线程使用模式,线程过多会带来调度的开销,进而影响缓存局部的和整体的性能。线程池维护多个线程,等待着监督管理者分配可并发执行的任务。

优点:降低资源消耗,提高响应速度。提搞可管理性

线程池的分类:

Executors.newFixedThreadPool(int)一个线程池,里面多个线程

Executors.newSingleThreadExecutor()一个线程池一个线程

Executors.newCachedThreadPool()缓存线程池,理论上可无限扩容

举例

newFixedThreadPool

package com.policy.thread.Thread202308.pool;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolDemo1 {public static void main(String[] args) {//fixedExecutorService threadpool1 = null;//5个窗口try {threadpool1 = Executors.newFixedThreadPool(5);for (int i = 0; i < 10; i++) {//执行threadpool1.execute(()->{System.out.println(Thread.currentThread().getName()+"办理业务");});}} catch (Exception e) {throw new RuntimeException(e);} finally {threadpool1.shutdown();}}
}

newSingleExecutor()

package com.policy.thread.Thread202308.pool;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolDemo1 {public static void main(String[] args) {//fixedExecutorService threadpool1 = Executors.newFixedThreadPool(5);//5个窗口ExecutorService threadpool2 = Executors.newSingleThreadExecutor();//一个线程try {for (int i = 0; i < 10; i++) {//执行threadpool2.execute(()->{System.out.println(Thread.currentThread().getName()+"办理业务");});}} catch (Exception e) {throw new RuntimeException(e);} finally {threadpool2.shutdown();}}
}

相当于开启了一个线程 只输出一个线程名

newCacheThreadPool()

package com.policy.thread.Thread202308.pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo1 {
    public static void main(String[] args) {
        //fixed
        ExecutorService threadpool1 = Executors.newFixedThreadPool(5);//5个窗口

        ExecutorService threadpool2 = Executors.newSingleThreadExecutor();//一个线程

        ExecutorService threadpool3 = Executors.newCachedThreadPool();

        try {

            for (int i = 0; i < 10; i++) {
                //执行
                threadpool3.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"办理业务");
                });
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            threadpool3.shutdown();
        }
    }
}

执行结果:

可以看到此处执行最多创建了7个线程,来执行一个循环任务,相当于开了七个窗口,理论上可扩充更灵活

底层实现

public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}

 三个线程池的底层都是new ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;
}

7个线程池参数:

int corePoolSize:常驻的核心线程的数量

int maximumPoolSize :最大的线程数量

long keepAliveTime, TimeUnit unit,存活时间 及存活时间的单位,非核心线程的空闲的存活时间,超出时间就会关闭掉

BlockingQueue<Runnable> workQueue,常驻的线程数量用完之后,进入阻塞队列

ThreadFactory threadFactory,线程工厂,用于创建线程

RejectedExecutionHandler handler拒绝策略

线程池的工作流程以及7个参数的使用

大致的流程图

执行了线程池的execute之后,线程池才会创建,

以上的图中核心线程数2 最大线程数5 阻塞队列数3

当有一个线程进到线程池之后,会最先进入核心线程中执行,如果核心线程此时已满,会加到阻塞队列中,如果阻塞队列长度也满了,那么会创建核心线程池之外的线程进行执行。如果最大线程池也满了,会根据线程策略进行操作

拒绝策略jdk内置的拒绝策略

AbortPolicy(默认) :直接抛出RejectedExecutionException异常,阻止系统正常运行。

CallerRunsPolicy:调用者运行,一种调节机制,该策略不会抛弃任务,也不会抛出异常,而是将任务回退给调用者,降低任务流量

DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入到队列中尝试再次提交当前任务

DiscardPolicy:该策略默默的丢弃无法处理的任务,不予以任何处理也不抛出异常。如果允许丢失任务,这是最好的策略

自定义线程池

线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor传参数的方式进行创建

原因1允许阻塞队列的请求长度是Integer.MAX_VALUE,可能会造成大量的线程堆积。导致OOM

实际中自己自定义线程池进行操作

Fork/join分支合并框架

可以将一个大任务,拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果进行输出。

FORK:把一个任务进行拆分,大事化小

Join:把拆分任务结果进行合并

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/777172.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQLite数据库文件损坏的可能几种情况(一)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;十三&#xff09; 下一篇&#xff1a;SQLite使用的临时文件&#xff08;二&#xff09; 概述 SQLite数据库具有很强的抗损坏能力。如果应用程序崩溃&#xff0c…

鸿蒙hdc使用指导

简介 hdc&#xff08;HarmonyOS Device Connector&#xff09;是HarmonyOS为开发人员提供的用于调试的命令行工具&#xff0c;通过该工具可以在windows/linux/mac系统上与真实设备或者模拟器进行交互。 环境准备 hdc工具通过HarmonyOS SDK获取&#xff0c;存放于SDK的toolch…

2024-3-28 市场情绪强修复

这一轮退潮负反馈都修复了&#xff0c; 艾艾精工 博信股份 安奈尔 永悦科技 大理药业 &#xff0c;高新发展 也补跌了&#xff0c;收尸队也干活了&#xff0c;情绪不修复不接力得最好写照。这轮周期 宁科生物 已经7板&#xff0c;已经追平了 博信股份7板&#xff0c;看明天溢…

Mac安装minio

Mac安装minio 本文介绍使用 mac 安装 MinIO。 所有软件安装优先参考官网&#xff1a;MinIO Object Storage for MacOS — MinIO Object Storage for MacOS #使用 brew 安装 minio brew install minio/stable/minio#找到 minio tong ~ $ brew list minio /opt/homebrew/Cella…

银行监管报送系统介绍(十二):非居民金融账户涉税信息报送

国家税务总局、财政部、中国人民银行、中国银行业监督管理委员会、中国证券监督管理委员会、国家金融监督管理总局2017年5月9日发布、2017年7月1日起施行的《非居民金融账户涉税信息尽职调查管理办法》。 一、《管理办法》出台的背景是什么&#xff1f;   受二十国集团&…

【unity】如何汉化unity Hub

相信大家下载安装unity后看着满操作栏的英文&#xff0c;英文不好的小伙伴们会一头雾水。但是没关系你要记住你要怎么高速运转的机器进入中国&#xff0c;请记住我给出的原理&#xff0c;不懂不代表不会用啊。现在我们就来把编译器给进行汉化。 第一步&#xff1a;我们打开Uni…

【VTKExamples::Points】第十一期 RadiusOutlierRemoval

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 公众号:VTK忠粉 前言 本文分享VTK样例RadiusOutlierRemoval,并解析接口vtkRadiusOutlierRemoval,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的…

【消息队列开发】 实现 MqClientTests 类——测试客户端

文章目录 &#x1f343;前言&#x1f333;所需属性&#x1f334;BeforeEach&#x1f332;AfterEach&#x1f38d;API测试⭕总结 &#x1f343;前言 本次开发任务 测试客户端接口 &#x1f333;所需属性 所需要一共三个属性 BrokerServer&#xff1a;服务器 ConnectionFa…

考研数学|武忠祥学习包搭配《660》和《880》

一、660、880、三大计算简单分析 660题 这本题册具有高难度、综合度和深度&#xff0c;属于高质量的题材。我建议不要在基础阶段就着手解决其中的660题&#xff0c;因为这可能会影响你的信心。相反&#xff0c;你可以在基础阶段完成一轮学习后&#xff0c;将这些题目留到强化…

安泰ATA-2161高压放大器在生物传感器研究中的应用

生物传感器&#xff08;biosensor&#xff09;&#xff0c;是一种对生物物质敏感并将其浓度转换为电信号进行检测的仪器&#xff0c;它利用固定化生物成分或生物体作为敏感元件。生物传感器并不专指用于生物技术领域的传感器&#xff0c;它的应用领域还包括环境监测、医疗卫生和…

市场复盘总结 20240328

仅用于记录当天的市场情况&#xff0c;用于统计交易策略的适用情况&#xff0c;以便程序回测 短线核心&#xff1a;不参与任何级别的调整&#xff0c;采用龙空龙模式 一支股票 10%的时候可以操作&#xff0c; 90%的时间适合空仓等待 二进三&#xff1a; 进级率中 40% 最常用的…

MySQL 索引:索引为什么使用 B+树?

Hash 索引不支持顺序和范围查询&#xff1b; 二叉查找树(BST)&#xff1a;解决了排序的问题&#xff0c;极端情况下可能会退化成线性链表&#xff0c;查询效率急剧下降&#xff1b; 平衡二叉树(AVL) &#xff1a;通过旋转解决了平衡的问题&#xff0c;但是旋转操作效率太低&am…

【推导结果】如何得到 回归均方误差 估计系数的标准误

对线性回归模型系数标准差标准误的理解 1.生成数据 yxe3.610.633.42-1.387.631.017.44-1.0111.651.3811.46-0.63 2.回归 y β 0 β 1 x ϵ y \beta_{0}\beta_{1}x\epsilon yβ0​β1​xϵ y i β 0 β 1 x i e i y_{i}\beta_{0}\beta_{1} x_{i}e_{i} yi​β0​β1​xi…

VTK——自定义二维图像涂抹Widget(支持任意值涂抹),擦除,恢复 vtkCustomPaintWidget

通过鼠标控制 涂抹区域&#xff0c;可以进行&#xff0c;后退&#xff0c;可以进行二维标注&#xff0c;也可以进行回退&#xff0c;也可以任意值涂抹。 vtkCustomPaintWidget 1.标注&#xff1a; 2.擦除 视频&#xff1a; 2D标注 vtkPaint VTK 2D 标注 描绘 2D 擦除&#x…

#Linux(SSH软件安装及简单使用)

&#xff08;一&#xff09;发行版&#xff1a;Ubuntu16.04.7 &#xff08;二&#xff09;记录&#xff1a; &#xff08;1&#xff09;终端键入&#xff08;root权限&#xff09;安装 apt-get install openssh-server 安装时遇到报错 E: Could not get lock /var/lib/dpkg/…

Java项目:78 springboot学生宿舍管理系统的设计与开发

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统的角色&#xff1a;管理员、宿管、学生 管理员管理宿管员&#xff0c;管理学生&#xff0c;修改密码&#xff0c;维护个人信息。 宿管员管理公寓…

快速上手Spring Cloud 十四:璀璨物联网之路

快速上手Spring Cloud 一&#xff1a;Spring Cloud 简介 快速上手Spring Cloud 二&#xff1a;核心组件解析 快速上手Spring Cloud 三&#xff1a;API网关深入探索与实战应用 快速上手Spring Cloud 四&#xff1a;微服务治理与安全 快速上手Spring Cloud 五&#xff1a;Spring …

蓝桥杯刷题计划-洛谷-持续更新

P8598 [蓝桥杯 2013 省 AB] 错误票据 题目 #include <bits/stdc.h> #define endl \n #define int long long #define INF 0x3f3f3f3f3f const int N 1000010; using namespace std; int arr[N]; signed main() {int N;cin>>N;int idx;while(cin>>arr[idx…

基于ssm的bbs论坛系统

开发环境&#xff1a;idea 前端&#xff1a;JQueryBootstraplayui后端&#xff1a;SpringSpringMVCMybatis数据库&#xff1a;mysqlredis 基于ssm的bbs论坛系统&#xff0c;功能有论坛、导读、动态、排行榜以及后台管理系统等等 话不多说&#xff0c;看图&#xff01;&#x…

HttpRunner 接口自动化测试框架实战,打造高效测试流程

简介 2018年python开发者大会上&#xff0c;了解到HttpRuuner开源自动化测试框架&#xff0c;采用YAML/JSON格式管理用例&#xff0c;能录制和转换生成用例功能&#xff0c;充分做到用例与测试代码分离&#xff0c;相比excel维护测试场景数据更加简洁。在此&#xff0c;利用业…