多线程5

本文介绍了Java中的阻塞队列实现(如MyBlockingQueue),探讨了线程池的原理,包括核心线程数、最大线程数、线程池任务队列(BlockingQueue)以及如何通过线程工厂管理和异常处理策略。重点讲解了线程池的工作机制,如任务的提交、线程的创建和回收,以及处理任务过多时的不同策略。
摘要由CSDN通过智能技术生成

阻塞队列

class MyBlockingQueue{
    private String[]elems=null;
    private volatile int head=0;
    private volatile int size=0;
    private volatile  int tail=0;
    public MyBlockingQueue(int capacity){
        elems=new String[capacity];
    }
    void put(String elem) throws InterruptedException {
        synchronized (this) {
            if (size >= elems.length) {
                this.wait();
                return;
            }
            elems[tail] = elem;
            tail++;
            if (tail >= elem.length()) {
                tail = 0;
            }
            size++;
            this.notify();
        }
    }
    String take() throws InterruptedException {
        synchronized (this) {
            if (size ==0) {
                this.wait();

            }
            String result= elems[head];
            head++;
            if (head >= elems.length) {
                head = 0;
            }
            size--;
        this.notify();
        return result;
    }
}
public class Demo1 {
    public static void main(String[] args) {

    }
}

wait不仅仅会被notify和notifyAll唤醒也可能被其他的操作唤醒比如interrupt。

优化再用wait方法的时候,应该搭配while判断条件的方式。这样的话就可以在被唤醒的时候再次确认,条件是否能再次成立,防止他覆盖到原来的哪些元素,当然这里的while循环对资源的调度是很小的,所以在执行了很多次以后就会忽略,防止了循环过多次而造成的死循环。

当然wait也是可以被interrupt打断的。

线程池

并发编程,一般会使用多进程,但是如果进程的任务很小,那么就会频繁的创建和销毁线程,这样就会消耗很多资源,这样就会降低效率。

直接创建/销毁线程,是需要用户态+内核态配合完成的工作。

线程池/协程,创建销毁,只通过用户态即可,不需要内核态的配合。如果使用线程池,提前把线程都创建好,放到用户态代码中写的数据结构里面后面用的时候,随时从池子里取,用完了放回池子里去这个过程,完全是用户态代码,不需要和内核进行交互。这将大大提高效率。

为什么调用内核态会大大降低效率呢?

是由于内核态不止会只有线程创建与销毁的任务,他还有其他的任务,但是任务的优先级都是大同小异的,所以一般线程的任务会等待,导致效率的降低。

  核心线程数

int corePoolSize

最大线程数

int maximumPoolSize

最大线程数=核心线程数+非核心线程数。

动态扩展一个线程池,刚被创建出来的时候,里面就包含核心线程数这么多的线程,

此时,线程池里就是包含4个线程线程池会提供一个submit方法,往里面添加任务.每个任务都是一个Runnable对象,如果当前添加的任务比较少,4个线程就足以能够处理,就只有4个线程在工作了,如果添加的任务比较多,4个线程处理不过来了.(有很多的任务在排队等待执行)这个时候,线程池就会自动创建出新的线程,来支撑更多的任务创建出来的线程总数,不能超过最大线程数过了一段时间之后,任务没那么多了,线程清闲了,部分线程就会被释放掉(回收了)回收只是把非核心线程回收掉,至少会保证线程池中线程数目不少于核心线程数。

就像公司招聘,如果公司压力大,那么就会招实习生,但是压力小的时候,就会辞退临时工。

线程数的设置,是根据具体情况来定的。但是大体可以分为两大类:

1.cpu密集型程序.

你的代码完成的逻辑,都是要通过cpu干活来完成的.

public class Demo2 {
    Thread thread=new Thread(()->{
        int count=0;
        for(int i=0;i<10000;i++){
            count++;
            System.out.println(count);
        }
    });

}

 这样的代码就会使cpu疯狂工作。

2.IO密集型程序.

你的代码大部分时间在等待IO(等待IO是不消耗CPU,不参与调度)

 Thread thread1=new Thread(()->{
        Scanner scanner=new Scanner(System.in);
        while (true){
            int a=scanner.nextInt();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    });

协程(纤程)和线程池的功能是相同的,但是方法的实现方式不同。

非核心线程,孕育最大空闲时间, 时间单位(s,min,h,ms).

long keepAliveTime  ,TimeUnit unit

非核心线程,在线程池不忙的时候,就会回收。

线程池的任务队列

BlockingQueue<Runnable> workQueue

是一个阻塞队列, 它可以用来存放任务。常用的实现类有`LinkedBlockingQueue`()、`ArrayBlockingQueue(数组)

工厂模式

不再使用构造方法创建对象给构造方法包装一层

  ThreadFactory threadFactory

这个线程工厂,主要是为了批量的给要创建的线程设置一些属性啥的线程工厂,在它工厂方法中,把线程的属性提前初始化好了,主要是解决,基于构造方法创建对象太坑了的问题,

当出现重载无法表示的问题的时候,就像

 public void zuobiao(int a,int b){
        
    }
    public void zuobiao(int r,int a){

    }

这样用笛卡尔坐标系和极坐标系的方式,这样的话就会造成重载(构造方法名字固定,类型和变量多少不一定)无法表示的方法这时候就需要用到工厂方法,虽然工厂方法不常用。

    public static A makexy(int x,int y){
        A a=new A();
        a.setX();
        a.setY();
        return a;
    }
    public static A makera(int r,int a){
        A a=new A();
        a.setr();
        a.seta();
        return a;
    }

        异常处理方式

RejectedExecutionHandler handler
 1.ThreadPoolExecutor.AbortPolicy,

直接抛出异常.(让程序猿快速的知道,任务处理不过来了,代码罢工了)

2.ThreadPoolExecutor.CallerRunsPolicy,

你给我这个线程池添加任务,不好意思,我这满了,你自己来执行谁负责添加任务,谁负责执行任务.线程池本身,不管了.

submit内部要做的事情不仅仅是入队列如果发现,队列满&&当前使用的这个拒绝策略,就会在submit内部自己去执行Runnable的run方法

3.ThreadPoolExecutor.DiscardoldestPolicy,

丢弃掉最老的任务.让新的任务去队列中排队

任务队列中队首的元素舍弃掉

4.ThreadPoolExecutor.DiscardPolicy

丢弃最新的任务,还是按照原有的节奏来执行

正在submit这个任务就不要了.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值