【JVM并发编程专题】——多线程管理(线程池)

线程池——底层逻辑

创建一个线程,是需要一定开销的;因为需要在内存中分配很多必要的环境;因此创建一个就丢掉在高并发环境下将频繁的发生,稀贵资源的频繁创建与丢弃;因此如果能提前创建好,并实现线程的复用,那将有利于提高性能;但是注意线程池中线程建的越多带来的弊端就是,内存负载增大;而如果你过多的创建了线程远大于你的cpu,实际上就反而造成了内存浪费,因为再多线程已经调度不过来了,倒不如直接拒绝掉,所以在线程定义中针对这些情况,我们可以配置线程参数来达到多方面平衡的目的;

核心线程:线程在初始化期间创建出来,这样使用完了扔给下一个可以重用;开销少,但会占用内存;
临时线程:线程用完了就扔掉,每次请求都会新建一个线程;开销大,但是节约内存;
线程池分类:周期、临时、定长;
线程池核心:队列、Wokder装饰器
对象池思想:池属性装饰器-引用-清洗
线程池应用:线程池一般只创建一次;但是执行submit、execute方法可以执行多次来创建多个线程;

线程池——线程池类型

单线程池:   ExecutorService executor=Executors.newSingleThreadExecutor();//串行执行线程,保证了访问顺序
定长线程池: ExecutorService executor=Executors.newFixedThreadPool(5);//--->全是核心!超过则阻塞队列,空闲则重用
缓存型池:  ExecutorService executor=Executors.newCachedThreadPool();//--->没有核心线程,全是临时线程;周期性短的异步任何可以用这个,超时移除
定时线程池:ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
	      Runnable task = new Runnable() {
    		public void run() {
        			System.out.println("HeartBeat.........................");
    		}
	};
	executor.scheduleAtFixedRate(task, 5, 3, TimeUnit.SECONDS);   //5秒后第一次执行,之后每隔3秒执行一次

线程池——自定义线程池

基础定义

时间和空间的选择;
new ThreadPoolExecutor(
    int corePoolSize,//核心线程池大小,核心线程池内及时没任务也不会清除,加入阻塞队列
    int maximumPoolSize,//总体线程池大小(核心+临时不能大于这个数,不然直接拒绝);
long keepAliveTime,//临时线程存货时间
    TimeUnit unit,//时间的单位
    BlockingQueue<Runnable> workQueue,//超过线程池大小的时的线程会被放到这里队列内,由外部传入
);
时间策略单位:
	TimeUnit.DAYS;               //天
	TimeUnit.HOURS;             //小时
	TimeUnit.MINUTES;           //分钟
	TimeUnit.SECONDS;           //秒
	TimeUnit.MILLISECONDS;      //毫秒
	TimeUnit.MICROSECONDS;      //微妙
	TimeUnit.NANOSECONDS;       //纳秒

应用举例

这种是继承实现,也可以用嵌入法实现
public class MyExcutorServcie extends ThreadPoolExecutor{
    public MyExcutorServcie(){
        super(
                1,//核心线程
                1,//总共线程
                1,//临时线程存货时间
                TimeUnit.MINUTES,//存活的时间单位
                new SynchronousQueue<Runnable>(),//阻塞队列
                new ThreadPoolExecutor.DiscardPolicy()//丢失任务时,抛出异常
        );
    };
}

 public static void main(String[] args) {
        MyExcutorServcie myExcutorServcie=new MyExcutorServcie();
        myExcutorServcie.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello word");
            }
        });
    }

线程池——加入任务方式

Runnable用法

 public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        myExcutorServcie.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello word");
            }
        });
 }

Callable用法

public static void main(String[] args) {
        List<Future<String>> resultList=new ArrayList<Future<String>>() ;
        ExecutorService executorService = Executors.newFixedThreadPool(8);

        /**
         * 创建10个线程,拿到fututre
         * fututre是一个访问结果的引用;只有线程执行完了才能通过fututre.get()拿到call返回的结果值
         */
        for(int i=1;i<=10;i++){
            Future<String> fututre = executorService.submit(new Callable<String>() {
                /**
                 * 线程结果访问值
                 * @return
                 * @throws Exception
                 */
                public String call() throws Exception {
                    String serviceResponse = service();
                    return serviceResponse;
                }

                /**
                 * 业务
                 * @return
                 * @throws Exception
                 */
                public String service() throws Exception{
                    Thread.sleep(500);
                    return "MOBIN";
                }
            });
            /**
             * 结果添加到队列中单线程轮询
             */
            resultList.add(fututre);
        }
        /**
         * 单线程轮询阻塞结果
         * 1000毫秒一次
         */
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                for(;;){
                    resultList.forEach(result->{
                        try{
                            if(result.isDone()){
                                System.out.println(result.get());     //打印各个线程(任务)执行的结果,把他从集合中删除也可以
                            }
                            Thread.sleep(1000);
                        }catch(InterruptedException e){
                            e.printStackTrace();
                        }catch(ExecutionException e){
                            e.printStackTrace();
                        }
                    });
                }
            }
        });
    }

Future用法

future.isDone();//判断线程是否执行完
future.get();//获取结果,如果未执行完则直接阻塞线程,很显然最好isDone判断一下再调用get是最好的

线程池——任务聚集策略

        new ThreadPoolExecutor.AbortPolicy();//丢弃任务并抛出RejectedExecutionException异常。
        new ThreadPoolExecutor.DiscardPolicy();//也是丢弃任务,但是不抛出异常。
        new ThreadPoolExecutor.DiscardOldestPolicy();//丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
        new ThreadPoolExecutor.CallerRunsPolicy();//由调用线程处理该任务

线程池——常见设计

CPU密集任务设计测路(核心线程:CPU核数 +1 ):
CPU密集型也叫计算密集型,指的是系统的硬盘、内存性能相对CPU要好很多,此时,系统运作大部分的状况是CPU Loading 100%,CPU要读/写I/O(硬盘/内存),I/O在很短的时间就可以完成,而CPU还有许多运算要处理,CPU Loading很高。因为这种任务已经跑完加线程也没啥意义,反而导致内存增多;
IO密集任务设计策略(核心线程:CPU核数 * 2):
IO密集型指的是系统的CPU性能相对硬盘、内存要好很多,此时,系统运作,大部分的状况是CPU在等I/O (硬盘/内存) 的读/写操作,此时CPU Loading并不高,所以不能让线程闲置,赋予更多的线程熟练
大神公式:核心线程数 = CPU核数 / (1-阻塞系数) 例如阻塞系数 0.8,CPU核数为4

线程池——原理(待更新)

JVM并发编程专题章节:
多线程框架
多线程测试

GodSchool
致力于简洁的知识工程,输出高质量的知识产出,我们一起努力
博主私人微信:supperlzf

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值