实战Java高并发程序设计(3.2 线程池)

1.Executor

jdk提供了一套Executor框架,本质上是一个线程池。

  1. newFixedThreadPool()方法:该方法返回一个固定数量的线程池。该线程池中的线程数量始终不变,当有一个新任务提交时,线程池中若有空闲线程,则立即执行,若没有,则任务会暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。
  2. newSingleThreadExecutor():该方法返回一个只有一个线程的线程池。若有多余一个任务被提交到该线程池,任务会被保存到一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。
  3. newCachedThreadPool():该方法返回一个可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在使用完毕后,将返回线程池进行复用。
  4. newSingleThreadScheduledExecutor():该方法返回一个ScheduledExecutorService对象,线程池大小为1。ScheduledExecutorService接口在ExecutorService接口之上扩展了在给定时间执行某任务的功能,如在某个固定的延时之后执行,或者周期性的执行某个任务。
  5. newScheduledThreadPool():该方法也返回一个ScheduledExecutorService对象,但该线程池可以指定线程数量。 
public class Test {
    public static class MyTask implements Runnable {
        @Override
        public void run() {
            System.out.println(System.currentTimeMillis() + ":Thread ID:" + Thread.currentThread().getId());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        MyTask myTask = new MyTask();
        ExecutorService es = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 5; i++) {
            es.submit(myTask);
        }
    }
}

       

2.拒绝策略     

当任务数量超过系统实际承载能力时,用拒绝策略进行补救。

  1. AbortPolicy():该策略会直接抛出异常,阻止系统正常工作。
  2. CallerRunsPolicy():只要线程池未关闭,该策略直接在调用者的线程中,运行当前被丢弃的任务。
  3. DiscardOldestPolicy():该策略将丢弃最老的一个请求,也就是即将被执行的任务,并尝试在次提交当前任务.
  4. DiscardPolicy():该策略默默地丢弃无法处理的任务,不予任何处理。
public class Test {
    public static class MyTask implements Runnable {
        @Override
        public void run() {
            System.out.println(System.currentTimeMillis() + ":Thread ID:" + Thread.currentThread().getId());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException{
        MyTask myTask = new MyTask();
        ExecutorService es = new ThreadPoolExecutor(5, 5, 0L,
                TimeUnit.MICROSECONDS, new LinkedBlockingDeque<Runnable>(10), Executors.defaultThreadFactory(), new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.out.println(r.toString()+" is discard");
            }
        });
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            es.submit(myTask);
            Thread.sleep(10);
        }
    }
}

                                                                        在执行几个任务后,拒绝策略就开始生效了。在实际应用中,可以利用这一点来分析系统的负载和任务丢失情况。

3.扩展线程池      

 ThreadPoolExecutor是一个可扩展的线程池。

public class Test {
    public static class MyTask implements Runnable {

        public String name;

        public MyTask(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            System.out.println("正在执行" + ":Thread ID:" + Thread.currentThread().getId() + ",Task name = " + name);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService es = new ThreadPoolExecutor(5, 5, 0L,
                TimeUnit.MICROSECONDS, new LinkedBlockingDeque<Runnable>()) {
            @Override
            protected void beforeExecute(Thread t, Runnable r) {
                System.out.println("准备执行:" + ((MyTask) r).name);
            }

            @Override
            protected void afterExecute(Runnable r,Throwable t){
                System.out.println("执行完成:"+((MyTask) r).name);
            }

            @Override
            protected void terminated(){
                System.out.println("线程退出");
            }
        };
        for (int i = 0; i < 5; i++) {
            MyTask myTask = new MyTask("TASK-GEYM-"+i);
            es.execute(myTask);
            Thread.sleep(10);
        }
        es.shutdown();
    }
}

       

所有任务的前中后时间点以及任务名字都可以捕捉。便于应用程序调试。

4.在线程池中捕获异常   

改造ThreadPoolExecutor方法,使其能抛出异常,以便于查询错误的地方。

public class Test extends ThreadPoolExecutor {

    public Test(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    @Override
    public void execute(Runnable task) {
        super.execute(wrap(task, clientTrace(), Thread.currentThread().getName()));
    }

    @Override
    public Future<?> submit(Runnable task) {
        return super.submit(wrap(task, clientTrace(), Thread.currentThread().getName()));
    }

    private Exception clientTrace() {
        return new Exception("Client stack trace");
    }

    private Runnable wrap(final Runnable task, final Exception clientStack, String clientThreadName) {
        return new Runnable() {
            @Override
            public void run() {
                try {
                    task.run();
                } catch (Exception e) {
                    e.printStackTrace();
                    throw e;
                }
            }
        };
    }

    public static void main(String[] args) {
        ThreadPoolExecutor pools = new Test(0, Integer.MAX_VALUE, 0L, TimeUnit.SECONDS,
                new SynchronousQueue<>());
        for (int i = 0; i < 5; i++) {
            pools.execute(new DivTask(100,i));
        }
    }

    private static class DivTask implements Runnable {
        int a, b;

        public DivTask(int a, int b) {
            this.a = a;
            this.b = b;
        }

        @Override
        public void run() {
            double re = a/b;
            System.out.println(re);
        }
    }
}

    

5.Fork/Join框架 

假如要处理1000个数据,但不具备同时处理的能力,先处理10个,在分阶段处理100次,最后将结果合并。某一线程处理完后可以帮助其他未完成的线程处理。

public class Test extends RecursiveTask<Long> {
    private static final int THRESHOLD = 10000;
    private long start;
    private long end;

    public Test(long start, long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        long sum = 0;
        boolean canConpute = (end - start) < THRESHOLD;
        if (canConpute) {
            for (long i = start; i < end; i++) {
                sum += i;
            }
        }else {
//            分成100个任务
            long step = (start+end)/100;
            ArrayList<Test> subTasks = new ArrayList<>();
            long pos = start;
            for (int i = 0; i < 100; i++) {
                long lastOne = pos+step;
                if (lastOne>end){
                    lastOne = end;
                }
                Test subTask = new Test(pos,lastOne);
                pos+=step+1;
                subTasks.add(subTask);
                subTask.fork();
            }
            for (Test t : subTasks){
                sum+=t.join();
            }
        }
        return sum;
    }

    public static void main(String[] args) {
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        Test test = new Test(0,200000L);
        ForkJoinTask<Long> result = forkJoinPool.submit(test);
        try {
            long res = result.get();
            System.out.println("sum = "+res);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_33283652/article/details/82964643