当前位置: 首页 > news >正文

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:把拆分任务结果进行合并

相关文章:

JUC内容概述

复习概念 Sleep和Wait的区别 Sleep是Thread的静态方法&#xff0c;wait是Object的方法&#xff0c;任何对象实例都可以使用sleep不会释放锁&#xff0c;他也不需要占用锁&#xff0c;暂停。wait会释放锁&#xff0c;但是调用他的前提是线程占有锁他们都可以被Interrupted方法…...

postcss安装和使用

要安装和使用 PostCSS&#xff0c;你可以按照以下步骤操作&#xff1a; 步骤一&#xff1a;安装 PostCSS 在项目目录下&#xff0c;通过 npm 初始化一个新的 package.json 文件&#xff08;如果还没有&#xff09;&#xff1a; npm init -y 安装 PostCSS 和必要的插件&#x…...

macOS 13 Ventura (苹果最新系统) v13.6.6正式版

macOS 13 Ventura是苹果电脑的全新操作系统&#xff0c;它为用户带来了众多引人注目的新功能和改进。该系统加强了FaceTime和视频通话的体验&#xff0c;同时优化了邮件、Safari浏览器和日历等内置应用程序&#xff0c;使其更加流畅、快速和安全。特别值得一提的是&#xff0c;…...

WordPress Git主题 响应式CMS主题模板

分享的是新版本&#xff0c;旧版本少了很多功能&#xff0c;尤其在新版支持自动更新后&#xff0c;该主题可以用来搭建个人博客&#xff0c;素材下载网站&#xff0c;图片站等 主题特点 兼容 IE9、谷歌 Chrome 、火狐 Firefox 等主流浏览器 扁平化的设计加响应式布局&#x…...

安卓国内ip代理app,畅游网络

随着移动互联网的普及和快速发展&#xff0c;安卓手机已经成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;由于地理位置、网络限制或其他因素&#xff0c;我们有时需要改变或隐藏自己的IP地址。这时&#xff0c;安卓国内IP代理App便成为了一个重要的工具。虎观代理…...

Day53:WEB攻防-XSS跨站SVGPDFFlashMXSSUXSS配合上传文件添加脚本

目录 MXSS UXSS&#xff1a;Universal Cross-Site Scripting HTML&SVG&PDF&SWF-XSS&上传&反编译(有几率碰到) SVG-XSS PDF-XSS Python生成XSS Flash-XSS 知识点&#xff1a; 1、XSS跨站-MXSS&UXSS 2、XSS跨站-SVG制作&配合上传 3、XSS跨站-…...

k8s安装traefik作为ingress

一、先来介绍下Ingress Ingress 这个东西是 1.2 后才出现的&#xff0c;通过 Ingress 用户可以实现使用 nginx 等开源的反向代理负载均衡器实现对外暴露服务&#xff0c;以下详细说一下 Ingress&#xff0c;毕竟 traefik 用的就是 Ingress 使用 Ingress 时一般会有三个组件: …...

如何在Windows 10中打开屏幕键盘?这里有详细步骤

本文解释了在Windows 10中打开或关闭屏幕键盘的不同方法&#xff0c;还解释了如何将屏幕键盘固定到开始菜单。 使用屏幕键盘的快捷键 如果你喜欢快捷方式&#xff0c;你会喜欢这个&#xff1a;按物理键盘上的WinCTRLO。这将立即显示屏幕键盘&#xff0c;而无需通过轻松使用。…...

【Pt】马灯贴图绘制过程 03-制作油渍、积尘效果

目录 效果 一、制作油渍效果 1.1 基本油渍 1.2 流淌的油渍痕迹 二、制作浮尘效果 三、制作积尘效果 效果 一、制作油渍效果 1.1 基本油渍 将上篇制作的“锈迹_深色”和“锈迹_浅色”两个文件夹再次合并为一个文件夹 这里就命名为“锈迹” 添加一个填充图层 设置Base …...

python-numpy-常用函数详解

文章目录 一、函数详解np.empty(num_points)np.zeros(shape, dtypefloat, orderC)np.tile(A, reps)np.newaxisnumpy.stack(arrays, axis0)np.roll(a, shift, axisNone) 二、实例矩阵进行扩展三行&#xff0c;使得每一行都与第一行相同二维数组每行减去不同的数 一、函数详解 n…...

UE小:基于UE5的两种Billboard material(始终朝向相机材质)

本文档展示了两种不同的效果&#xff0c;分别是物体完全朝向相机和物体仅Z轴朝向相机。通过下面的演示和相关代码&#xff0c;您可以更加直观地理解这两种效果的差异和应用场景。 1. 完全朝向相机效果 此效果下&#xff0c;物体将完全面向相机&#xff0c;不论相机在哪个角度…...

spring boot actuator 安全配置 springboot的安全性

关于springboot Actuator框架的安全配置方案&#xff1a; 加入security安全验证框架 方案一&#xff1a; 配置信息&#xff1a; spring:security:user:password: adminname: adminmanagement:endpoints:web:base-path: /monitorexposure:include: "*"# 排除端点e…...

macOS Sonoma如何查看隐藏文件

在使用Git进行项目版本控制时&#xff0c;我们可能会遇到一些隐藏文件&#xff0c;比如.gitkeep文件。它通常出现在Git项目的子目录中&#xff0c;主要作用是确保空目录也可以被跟踪。 终端命令 在尝试查看.gitkeep文件时&#xff0c;使用Terminal命令来显示隐藏文件 default…...

深入浅出:语言模型的原理、实战与评估

深入浅出&#xff1a;语言模型的原理、实战与评估 1. 引言1.1. 关于语言模型1.2. 语言模型的重要性 2. 语言模型简介2.1. 语言模型的类型2.2. 技术演进 3. 语言模型的原理3.1. 概率基础3.2. 深度学习模型 4. 语言模型的实战应用4.1. 数据准备4.2. 模型训练4.3. 应用场景 5. 语言…...

基于ssm的线上旅行信息管理系统论文

摘 要 随着旅游业的迅速发展&#xff0c;传统的旅行信息查询管理方式&#xff0c;已经无法满足用户需求&#xff0c;因此&#xff0c;结合计算机技术的优势和普及&#xff0c;特开发了本线上旅行信息管理系统。 本论文首先对线上旅行信息管理系统进行需求分析&#xff0c;从系…...

Jupyter开启远程服务器(最新版)

Jupyter Notebook 在本地进行访问时比较简单&#xff0c;直接在cmd命令行下输入 jupyter notebook 即可&#xff0c;然而notebook的作用不止于此&#xff0c;还可以用于远程连接服务器&#xff0c;这样如果你有一台服务器内存很大&#xff0c;但是呢你又不喜欢在linux上进行操作…...

【SpringCloud微服务实战10】DevOps自动化部署微服务项目(Jenkins+Docker+K8s)

一、什么是 DevOps DevOps 是一种重视软件开发人员(Developer)和运维人员(Operations)之间沟通与协作的文化、运动或实践,目标在于快速交付高质量的软件产品和服务。DevOps 强调自动化流程、持续集成与交付(CI/CD)、以及通过工具链、敏捷方法论和跨职能团队协作来增强软…...

DSVPN实验报告

一、分析要求 1. 配置R5为ISP&#xff0c;只能进行IP地址配置&#xff0c;所有地址均配为公有IP地址。 - 在R5上&#xff0c;将接口配置为公有IP地址&#xff0c;并确保只进行了IP地址配置。 2. R1和R5之间使用PPP的PAP认证&#xff0c;R5为主认证方&#xff1b;R2于R5之间…...

Linux:Jenkins:参数化版本回滚(6)

上几章我讲到了自动集成和部署 Linux&#xff1a;Jenkins全自动持续集成持续部署&#xff08;4&#xff09;-CSDN博客https://blog.csdn.net/w14768855/article/details/136977106 当我们觉得这个页面不行的时候&#xff0c;需要进行版本回滚&#xff0c;回滚方法我这里准备了…...

Haproxy2.8.1+Lua5.1.4部署,haproxy.cfg配置文件详解和演示

目录 一.快速安装lua和haproxy 二.配置haproxy的配置文件 三.配置haproxy的全局日志 四.测试负载均衡、监控和日志效果 五.server常用可选项 1.check 2.weight 3.backup 4.disabled 5.redirect prefix和redir 6.maxconn 六.调度算法 1.静态 2.动态 一.快速安装lu…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...