多线程编程细节

线程池应用编程实现

  使用固定大小的线程池

public class Test1 {

        public static void main(String[] args) throws InterruptedException, ExecutionException {

                ExecutorService es = Executors.newFixedThreadPool(3);

                //计算1+2+3+……+1000,启动10个工作任务

                Future [] fs = new Future[10];

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

                        int begin =i*100+1;

                        int end =(i+1)*100;

                        Callable<Integer> caller = new MyCallable(begin,end);

                        fs[i]=es.submit(caller);

                }

                int res=0;

                for (int i = 0; i < fs.length; i++) {

                        Object kk = fs[i].get();

                        if (kk!=null && kk instanceof Integer ) {

                                res+=(Integer)kk;

                        }

                }

                es.shutdown();

                System.out.println("1+2+3+……+1000="+res);

        }

}



class MyCallable implements Callable<Integer>{

        private int begin,end;

        

    public MyCallable(int begin,int end) {

        this.begin=begin;

        this.end=end;                

        }

        @Override

        public Integer call() throws Exception {

                System.out.println(Thread.currentThread());

                int res=0;

                for (int i = begin; i < end; i++) {

                        res+=i;

                }

                return res;

        }

}

使用缓存线程池

public class Test2 {

        public static void main(String[] args) throws Exception {

                ExecutorService es = Executors.newCachedThreadPool();

                // 计算1+2+3+……+1000,启动10个工作任务

                Future[] fs = new Future[10];

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

                        int begin = i * 100 + 1;

                        int end = (i + 1) * 100;

                        Callable<Integer> caller = new MyCallable(begin, end);

                        fs[i] = es.submit(caller);

                }

                int res = 0;

                for (int i = 0; i < fs.length; i++) {

                        Object kk = fs[i].get();

                        if (kk != null && kk instanceof Integer) {

                                res += (Integer) kk;

                        }

                }

                es.shutdown();

                System.out.println("1+2+3+……+1000=" + res);

        }

}



class MyCallable implements Callable<Integer> {

        private int begin, end;



        public MyCallable(int begin, int end) {

                // TODO Auto-generated constructor stub

                this.begin = begin;

                this.end = end;

        }

        @Override

        public Integer call() throws Exception {

                // TODO Auto-generated method stub

                System.out.println(Thread.currentThread());

                int res = 0;

                for (int i = begin; i < end; i++) {

                        res += 1;

                }

                return res;

        }

}

ThreadPoolExecutor

在具体开发中一般不建议直接使用系统预定义的线程池【ali】,而是通过ThreadPoolExecutor进行自定

义线程池

ThreadPoolExecutor是线程池框架的一个核心类,线程池提供了线程对象的复用机制,并对线程进行统

一管理

  1.降低系统资源消耗

  2.提高响应速度

  3.提高线程的可管理性

线程池的运行状态有5种

  1.Running高3位位111,可以接收新任务并处理阻塞队列中的任务

  2.shutdown高3位为000,不接收新任务但是会处理阻塞队列中的任务

  3.stop高3位为001,不会接收新任务,也不会处理阻塞队列中的任务,并且中断正在运行的任务

  4.tidying高3为010,所有任务都终止,工作线程数为0

  5.terminated高3为011,中断任务执行阶段结束

构造器函数

    1

    2

    3

    4

    5

public static ExecutorService newCachedThreadPool() {

        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

                60L, TimeUnit.SECONDS,

                new SynchronousQueue<Runnable>());

}

构造器定义

    1

    2

    3

    4

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long

        keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory

        threadFactory,RejectedExecutionHandler handler)

}

1.corePoolSize用于配置线程池中核心线程数

2.maximumPoolSize用于设置线程池中允许的最大线程数。当阻塞队列满了之后,继续提交任务则

   创建性的线程执行任务

3.keepAliveTime用于配置空闲线程的存活时间。默认情况下只有当线程池的线程数大于

  corePoolSize这个参数才会生效。当一个工作线程的空闲时间到达这个值时,这个线程会自动终

  止,直到线程数不超过corePoolSize为止。一般核心线程不会自动终止,除非调用方法

  allowCoreThreadTimeout(boolean)配置

4.unit就是keepAliveTime参数的时间单位,是一个枚举类型值

5.workQueue任务缓存队列,用于存放等待执行的任务。如果当前线程数为corePoolSize时,继续

  提交的任务就会被缓存到任务队列中,等待被调度执行。

    1.SynchronousQueue是一个不存储元素的阻塞队列,每个插入操作必须等待另外线程调用移

      除操作,否则插入操作一直处于阻塞等待状态

    2.LinkedBlockingQueue是一种基于链表结构的阻塞队列,是一种无界队列

    3.ArrayBlockingQueue是一个基于数组结构的有界阻塞队列,会按照FIFO的规则排序任6.ThreadFactory线程工作,用于创建新线程时使用的工厂类

7.handler设置任务拒绝策略,当阻塞队列满,而且线程池中线程数已经到达了maximumPoolSize,

   如果继续提交任务,就会采用任务拒绝策略处理新任务

      1.AbortPolicy丢弃任务,并且抛出异常,是默认拒绝策略

      2.CallerRunsPolicy由调用execute方法提交任务的线程自己执行任务

      3.DiscardPolicy丢弃任务,但是不抛出异常

      4.DiscardOldestPolicy 丢弃任务队列中最前面的任务,然后重新尝试执行任务

同时也允许根据应用场景实现RejectedExecutionHandler接口自定义饱和策略,例如记录日志或者

持久化存储不能处理的任务

Executors

Executors是一个用户创建线程池的工具类

 1.newFixedThreadPool用于创建一个固定大小的定长线程池,可以控制线程的最大并发数,超出的

   线程会在队列中等待

     1.因为采用的是无界队列,而且实际线程数永远不会变化,适用于可以预测线程数量的业务中,

       或者服务器负载较重的场景下,对当前的线程数量进行限制

     2.由于是无界队列可以会导致大量的任务积压

    1

    2

    3

    4

    5

    6

public static ExecutorService newFixedThreadPool(int nThreads) {

        return new ThreadPoolExecutor(nThreads, nThreads,0L,

        TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());

        //核心线程数=最大线程数,所以keepAliveTime设置无效,任务队列采用

        //LinkedBlockingQueue无界队列

}

2.newCachedThreadPool用于创建一个可缓存的线程池,如果线程池长度超过处理需求,可以灵活

的回收空闲线程资源,如果没有可回收重用线程时会自动新建线程

  1.可以用来创建一个可以无限扩大的线程池(最大线程数Integer.MAX_VALUE),适用于服务

     器负载较轻,执行很多短期异步任务的场景下

    1

    2

    3

    4

    5

    6

public static ExecutorService newCachedThreadPool() {

        return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,

        new SynchronousQueue<Runnable>());

        //核心线程数0<最大线程数Integer.MAX_VALUE,所以keepAliveTime设置有效,一个线程最

        //大空闲时间为60s

}

3.newSingleThreadExecutor用于创建只有一个线程的定长线程值,只用唯一的工作线程来执行任

  务,保证所有的任务按照FIFO或者LIFO顺序执行

   1.适用于需要保证顺序执行各个任务的场景下,而且需要保证在任意的时间点上不会出现多个任

     务同时执行

    1

    2

    3

    4

    5

public static ExecutorService newSingleThreadExecutor() {

        return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1,

        1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));

        核心线程数1=<最大线程数1,所以所以keepAliveTime设置无效,任务队列采用

        //LinkedBlockingQueue无界队列

4.newScheduledThreadPool创建一个变长的线程池,并且支持定时及周期性任务的执行

   1.可以延时启动、定时执行的线程池,适用于需要多个后台线程执行周期性任务的场景下

    1

    2

    3

    4

    5

    6

    7

    8

    9

   10

public static ScheduledExecutorService newScheduledThreadPool(int

        corePoolSize) {

        return new ScheduledThreadPoolExecutor(corePoolSize);

}

public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor

        implements ScheduledExecutorService

        public ScheduledThreadPoolExecutor(int corePoolSize) {

        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new

        DelayedWorkQueue());

}

5.newWorkStealingPool创建一个拥有多个任务队列的线程池

    创建当前可用cpu数量的线程来并行执行,适用于比较耗时的操作同时并行执行的场景下

提交任务的方式

线程池提供了2种任务提交方法submit和execute,一般通过submit提交任务是用于可以有返回值的时

候,通过execute提交的任务不能获取任务的执行结果

execute的方法

public class Test3 {

        public static void main(String[] args) {

                ExecutorService es = Executors.newFixedThreadPool(3);

                es.execute(() -> {

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

                                System.out.println("Hello " + i);

                                try {

                                        Thread.sleep(200);

                                } catch (InterruptedException e) {

                                        e.printStackTrace();

                                }

                        }

                });

                System.out.println("main........");

        }

}

submit的方法

public class Test4 {

        public static void main(String[] args) throws InterruptedException, ExecutionException {

                ExecutorService es = Executors.newFixedThreadPool(3);

                es.submit(() -> {

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

                                System.out.println("Hello " + i);

                                try {

                                        Thread.sleep(200);

                                } catch (InterruptedException e) {

                                        e.printStackTrace();

                                }

                        }

                });

                System.out.println("main........");

                ExecutorService es1 = Executors.newFixedThreadPool(3);

                Future f = es1.submit(() -> {

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

                                System.out.println("Hello " + i);

                                try {

                                        Thread.sleep(200);

                                } catch (InterruptedException e) {

                                        e.printStackTrace();

                                }

                        }

                });

                f.get(); // 可以通过get接收子线程的执行结果,也可以到达阻塞主线程,等待子线程执行完成的效果

                System.out.println("main........");

        }

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值