• Java线程池应用


    在Java中,多线程有着广泛运用。在实际应用中,好的软件设计不建议手动创建和销毁线程。线程的创建和销毁是非常耗 CPU 和内存资源的,因为这需要 JVM 和操作系统的参与。为此,我们在面临多线程问题时,通常会采用线程池。一般情况下,每个线程池会由这些模块组成:一个任务队列,一个工作线程的集合,一个线程工厂,管理线程状态的元数据。

    线程池可以解决两个问题:一是由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法;二是每个 ThreadPoolExecutor 还维护着一些基本的统计数据,如完成的任务数。 

    线程池均位于 java.util.concurrent包中。
    
    ThreadPoolExecutor类的继承关系为:
    
    public class ThreadPoolExecutor extends AbstractExecutorService
    
    其中,抽象类 AbstractExecutorService的继承关系为:
    
     public abstract class AbstractExecutorService extends Object implements ExecutorService
    
    ExecutorService接口的继承关系为:
    
    public interface ExecutorService extends Executor 
    
    Executor是一个顶级接口。  

      Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。比较重要的几个类:

    ExecutorService

    真正的线程池接口。

    ScheduledExecutorService

    能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。

    ThreadPoolExecutor

    ExecutorService的默认实现。

    ScheduledThreadPoolExecutor

    继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现。

    在实际应用中,类Executors为我们提供了几个生成线程池的重要方法:Executors.newCachedThreadPool(),Executors.newFixedThreadPool(int),Executors.newSingleThreadExecutor()等。其中:

    1. newSingleThreadExecutor
    创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
    2.newFixedThreadPool
    创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
    3. newCachedThreadPool
    创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
    4.newScheduledThreadPool
    创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
    

      Executors的的继承关系为:

    public class Executors extends Object 
    

      由于创建子线程可以有继承Thread类,实现Runnable接口,以及实现Callable接口三种方式,所以,我这里先通过这三种方式创建线程,然后再通过一个测试类通过线程池来运行。

    package com.itszt.test;
    
    import java.util.concurrent.*;
    
    /**
     * 线程池
     */
    public class Test2 {
        //采用newFixedThreadPool()方法创建线程池,设置线程池中有2个线程
        //static ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
        //或者采用下述方式生成线程连接池
        static ExecutorService pool = Executors.newFixedThreadPool(2);
    
        public static void main(String[] args) {
            Future<String> s1 = pool.submit(new MyCall());
            Future<String> s2 = pool.submit(new MyCall());
            try {
                System.out.println(s1.get());
                System.out.println(s2.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            //切记:线程池不是线程执行结束就终止,而是手动终止
            pool.shutdown();
        }
    
        public static void main2(String[] args) {
            pool.submit(new MyRun("张三"));
            pool.submit(new MyRun("李四"));
            pool.submit(new MyRun("王五"));
            pool.submit(new MyRun("赵六"));
            //切记:线程池不是线程执行结束就终止,而是手动终止
            pool.shutdown();
        }
    
        public static void main1(String[] args) {
            pool.submit(new MyThread("张三"));
            pool.submit(new MyThread("李四"));
            pool.submit(new MyThread("王五"));
            pool.submit(new MyThread("赵六"));
            //切记:线程池不是线程执行结束就终止,而是手动终止
            pool.shutdown();
        }
    }
    
    //通过继承Thread创建线程
    class MyThread extends Thread {
        public MyThread(String name) {
            super(name);
        }
    
        int num = 10;
    
        @Override
        public void run() {
            while (num >= 0) {
                try {
                    Thread.sleep(100);//线程休眠
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "正在数:" + num);
                num--;
            }
        }
    }
    
    //通过实现Runnable接口创建线程
    class MyRun implements Runnable {
        public MyRun(String name) {
            Thread.currentThread().setName(name);
        }
    
        int num = 10;
    
        @Override
        public void run() {
            while (num >= 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "正在数:" + num);
                num--;
            }
        }
    }
    
    //通过实现Callable接口创建线程
    class MyCall implements Callable<String> {
        int num = 10;
    
        @Override
        public String call() throws Exception {
            while (num >= 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "正在数:" + num);
                num--;
            }
            return Thread.currentThread().getName() + "顺利执行";
        }
    }
    

      上述代码执行结果如下:

    pool-1-thread-1正在数:10
    pool-1-thread-2正在数:10
    pool-1-thread-1正在数:9
    pool-1-thread-2正在数:9
    pool-1-thread-1正在数:8
    pool-1-thread-2正在数:8
    pool-1-thread-2正在数:7
    pool-1-thread-1正在数:7
    pool-1-thread-1正在数:6
    pool-1-thread-2正在数:6
    pool-1-thread-1正在数:5
    pool-1-thread-2正在数:5
    pool-1-thread-2正在数:4
    pool-1-thread-1正在数:4
    pool-1-thread-1正在数:3
    pool-1-thread-2正在数:3
    pool-1-thread-2正在数:2
    pool-1-thread-1正在数:2
    pool-1-thread-1正在数:1
    pool-1-thread-2正在数:1
    pool-1-thread-1正在数:0
    pool-1-thread-2正在数:0
    pool-1-thread-1顺利执行
    pool-1-thread-2顺利执行  
  • 相关阅读:
    Asp.net并发请求导致的数据重复插入问题
    记一次完整的asp.net-mvc页面优化过程
    设计完美的策略模式,消除If-else
    EF|CodeFirst数据并发管理
    mongo upsert
    js回调函数传参
    使用poi时,两个环境下,一个错误一直正常
    jna笔记1
    springboot集成rabbitmq测试
    一个方法让你了解js中的细节
  • 原文地址:https://www.cnblogs.com/lizhangyong/p/8146014.html
Copyright © 2020-2023  润新知