多线程6

本文详细介绍了Java中的线程池,包括ExecutorService的几种创建方式,线程池的构成要素,如任务队列和提交方法。还探讨了如何在MyThreadPool中实现线程数量动态调整,以及定时器的使用和优化,以避免忙等和资源消耗。
摘要由CSDN通过智能技术生成

线程池 

标准库中的线程池

     ExecutorService service=Executors.newCachedThreadPool();//根据任务数目,自动进行扩容 
     Executors.newFixedThreadPool(4);//创建固定线程数目的线程池
     Executors.newSingleThreadExecutor();//创建一个只包含单个线程的线程池
     Executors.newScheduledThreadPool(4);//创建一个固定的线程数,但是任务演示执行的线程池。

 线程池的应用

    public static void main(String[] args) {
        ExecutorService service=Executors.newCachedThreadPool();//根据任务数目,自动进行扩容
      for (int i=0;i<10000;i++) {
         
          service.submit(new Runnable() {
              @Override
              public void run() {
                  System.out.println( i+ Thread.currentThread().getName());
              }
          });

      }

上述中 i  存在问题,这是变量捕获问题,i一直在改变不能在print中使用,所以更改代码如下

   public static void main(String[] args) {
        ExecutorService service=Executors.newCachedThreadPool();//根据任务数目,自动进行扩容
      for (int i=0;i<10000;i++) {
          int id=i;
          service.submit(new Runnable() {
              @Override
              public void run() {
                  System.out.println( id+ Thread.currentThread().getName());
              }
          });

      }

创建线程池

一个线程池要包含哪些东西?

1)有若干个线程

2)有任务队列.(使用Runnable即可)

3)提供submit方法



import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;

class  MyThreadPool{
    private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);

    public  MyThreadPool(int n){
    for (int i=0;i<n;i++){
        Thread t=new Thread(()->{
         while (true) {
             try {
                 Runnable runnable = queue.take();
                 runnable.run();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
        });
        t.start();
    }
    }
    void subimt(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }
}
public class Test1 {
    public static void main(String[] args) {
        MyThreadPool threadPool=new MyThreadPool(10);

        for(int i=0;i<1000;i++){

            int id=i;
            try {
                threadPool.subimt(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println( id+ Thread.currentThread().getName());
                    }
                });
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }
    }

}

main线程的任务是先是创建对象,通过调用MyThreadPoll的构造方法来创建n个线程,然后各个线程进入无限循环,然后等到有任务进入,然后通过sbimt方法添加到任务队列queue,然后到任务队列,任务队列将其分布到各个线程最后达到线程池的作用。


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;

class  MyThreadPool2{
    private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);
        private  int maxPoolSize=50;
        private List<Thread> threadList=new ArrayList<>();
    public  MyThreadPool2(int n,int maxPoolSize){
            this.maxPoolSize=maxPoolSize;
        for (int i=0;i<n;i++){
            Thread t=new Thread(()->{
                while (true) {
                    try {
                        Runnable runnable = queue.take();
                        runnable.run();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
        threadList.add(t);
        }
    }
    void subimt(Runnable runnable) throws InterruptedException {
            //此处进行判定,判定说当前任务队列的元素个数,是否比较长
        //如果队列元素比较长,说明已有的线程,不太能处理过来了、创建新的线程即可,
        // 如果队列不是很长,没必要创建新的线程.
        queue.put(runnable);
        if(queue.size()>=500&& threadList.size()<maxPoolSize ){

                Thread t=new Thread(()->{
                    while (true) {
                        try {
                            Runnable take = queue.take();
                            runnable.run();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });
                t.start();
            }

    }
}
public class Test2 {
    public static void main(String[] args) {
        MyThreadPool2 threadPool2=new MyThreadPool2(20.10);

        for(int i=0;i<1000;i++){

            int id=i;
            try {
                threadPool2.subimt(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println( id+ Thread.currentThread().getName());
                    }
                });
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }
    }

}

可以将线程数加入对应的队列,然后就可以实现最大线程的限制,但是最大线程的限制条件在submit函数中应用

实现拒绝策略的核心,在submit这里

2)submit的时候,先判定当前任务队列元素是否已经比较多了(自行设定一个阈值,比如,900)

3)如果确实比较多了,就根据刚才构造时指定的拒绝策略,执行不同的逻辑,

a)直接抛出异常,

b)直接在submit中调用Runnable的run.

c)删除队列的队首元素 (可以一次删多个,也不一定是一个)

d)丢弃当前元素,不添加到队列中.

定时器

定时器,就是“闹钟"效果

指定一个任务(Runnable),并且指定一个时间(3000ms),此时这个任务不会立即执行,而是在时间到达之后,再去执行。

定时器的应用

第一个参数是一个抽象类,本质上还是实现了Runnable.就把它当做Runnable来使用即可.


import java.util.Timer;
import java.util.TimerTask;

public class Test3 {
    public static void main(String[] args) {
        Timer timer=new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(3000);
            }
        },3000);
    }
}

线程不会结束,由于Timer中包含了前台宪政,阻止了进程的结束。

(TimerTasktask,longdelay)

表示"多长时间之后”执行.以当前执行schedule的时刻为基准,继续等delay时间之后再去进一步的执行.

创建定时器

需求:

1)能够延时执行任务/指定时间执行任务

2)能够管理多个任务

1.定义一个类,表示一个任务(Runnable)
class MyTimerTask{
    private  Runnable runnable;
    private long time;
    public  MyTimerTask(Runnable runnable){
        this.runnable=runnable;
        this.time=System.currentTimeMillis()+time;
    }
    public void run(){
        runnable.run();
    }
    public  long getTime(){
        return time;
    }
}
2.通过一定的数据结构,保存多个任务,
class MyTimer{
    private List<MyTimerTask> taskList=new ArrayList<>();
    public void schedule(Runnable runnable,long delay){
        MyTimerTask timerTask=new MyTimerTask(runnable,delay);
        taskList.add(timerTask);

    }
}

 这样会造成不停的扫描操作,这样会消耗太多资源,可以应用优先级队列。

可以把这些任务通过优先级队列保存起来.按照时间作为优先级的先后的标准就可以做到,队首元素就是时间最靠前的任务

class MyTimer{
    private PriorityQueue<MyTimerTask> taskList=new PriorityQueue<>();
    public void schedule(Runnable runnable,long delay){
        MyTimerTask timerTask=new MyTimerTask(runnable,delay);
        taskList.add(timerTask);

    }
}
3.还需要有一个线程,来负责执行这里的任务.(在指定的时间去执行)

构造方法中,创建一个线程,用新的线程来执行队列中的任务,

public MyTimer(){
        Thread thread=new Thread(()->{
           while (true){
               if(taskList.size()==0){
                   continue;
               }
               MyTimerTask timerTask=taskList.peek();
               long curTime=System.currentTimeMillis();
               if(curTime>=timerTask.getTime()){
                   taskList.poll();
               }else {
                   continue;
               }
           }
        });
    }

优化,会有线程安全所以要加锁,要不然会出现重复扫描的问题。

import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;

class MyTimerTask{
    private  Runnable runnable;
    private long time;
    public  MyTimerTask(Runnable runnable, long delay){
        this.runnable=runnable;
        this.time=System.currentTimeMillis()+delay;
    }
    public void run(){
        runnable.run();
    }
    public  long getTime(){
        return time;
    }
}
class MyTimer{
    Object o=new Object();
    private PriorityQueue<MyTimerTask> taskList=new PriorityQueue<>();
    public void schedule(Runnable runnable,long delay){
        synchronized (o) {
            MyTimerTask timerTask = new MyTimerTask(runnable, delay);
            taskList.add(timerTask);
        }
    }
    public MyTimer(){

        Thread thread=new Thread(()->{
           while (true) {
               synchronized (o) {
                   if (taskList.size() == 0) {
                       continue;
                   }
                   MyTimerTask timerTask = taskList.peek();
                   long curTime = System.currentTimeMillis();
                   if (curTime >= timerTask.getTime()) {
                       taskList.poll();
                   } else {
                       continue;
                   }
               }
           }
        });
        }
    }

}

现在存在忙等状态

上述代码就会短时间内循环很多次.上述操作都是在王"空转”一直在持续消耗cpu,但是没有真正执行任务。

 try {
                           o.wait(curTime-timerTask.getTime());
                       } catch (InterruptedException e) {
                           throw new RuntimeException(e);
                       }

此处应用wait方法不用sleep

1.notify唤醒wait,属于常规编程手法(处理正常业务流程)通过interrupt唤醒sleep,非常规手法.(处理异常业务流程)

2.sleep会抱锁,wait不会抱锁

这个代码中,不太适合直接使用PriorityBlockingQueue

只能处理,队列为空时候的阻塞,如果使用上述阻塞版本,还需要通过额外的锁对象和wait来实现针对时间未到的情冰

比较肯定要写构造方法:如下

最终写出的个人task如下:

import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;

class MyTimerTask implements Comparable<MyTimerTask>{
    private  Runnable runnable;
    private long time;
    public  MyTimerTask(Runnable runnable, long delay){
        this.runnable=runnable;
        this.time=System.currentTimeMillis()+delay;
    }
    public void run(){
        runnable.run();
    }
    public  long getTime(){
        return time;
    }

    @Override
    public int compareTo(MyTimerTask o) {
        return (int) (this.time-o.time);
    }
}
class MyTimer{
    Object o=new Object();
    private PriorityQueue<MyTimerTask> taskList=new PriorityQueue<>();
    public void schedule(Runnable runnable,long delay){
        synchronized (o) {
            MyTimerTask timerTask = new MyTimerTask(runnable, delay);
            taskList.add(timerTask);
        }
    }
    public MyTimer(){

        Thread thread=new Thread(()->{
           while (true) {
               synchronized (o) {
                   if (taskList.size() == 0) {
                       continue;
                   }
                   MyTimerTask timerTask = taskList.peek();
                   long curTime = System.currentTimeMillis();
                   if (curTime >= timerTask.getTime()) {
                       taskList.poll();
                   } else {
                       try {
                           o.wait(curTime-timerTask.getTime());
                       } catch (InterruptedException e) {
                           throw new RuntimeException(e);
                       }
                   }
               }
           }
        });
        }
    }

}
public class Test4 {
    public static void main(String[] args) {

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值