JAVA4大线程池

      不知不觉中我们电脑的硬件设施越来越好,从双核四线程普及到如今四核八线比比皆是。互联网发展至今,讲究的就是快,less is more,而且大数据的诞生和各种种类繁多的需求处理,单线程的程序逐渐不能满足一些业务需求。于是多线程就如此登上我们的舞台。

       Java是如何实现和管理线程池的? 
       从JDK 5开始,把工作单元与执行机制分离开来,工作单元包括Runnable和Callable,而执行机制有Executor框架提供。在HotSpot VM的线程模型中,Java线程被一对一映射为本地操作系统线程。Java线程启动时会创建一个本地操作系统线程;当Java线程终止时,这个操作系统线程也会被回收。操作系统会调用所有线程并将他们分配给可用的CPU。
可以将此种模式分为两层,在上层,Java多线程程序通常把应用程序分解为若干任务,然后使用用户级的调度器(Executor框架)讲这些任务映射为固定数量的线程;在底层,操作系统内核将这些线程映射到硬件处理器上。

        使用线程池的好处有很多:

        1、降低资源消耗(线程无限制地创建,然后使用完毕后销毁,线程与线程之前切换占用的cpu资源也会大大减小,因为他们本身就是出自同一个容器资源中) 

        2、提高响应速度(无须再次创建线程)

        3、提高线程的可管理性(我们可以自己在线程池中设置允许的最大线程数,线程空闲时的存活时间等等)

        这里先简单介绍一下我们常用的已经在JDK中封装好的线程池:Executors,这里我们简单介绍常用的三个:

        先上我的测试线程实现类:

package cn.com.sh.gx.crawler.extactor;

public class TestThreads implements Runnable {
    private int index;
    public TestThreads(int index) {
        this.index=index;
    }


    @Override
    public void run() {
        while (true){
            System.out.println("=======2222=====");
            System.out.println(index);
            try{
                Thread.sleep(2000);
            }catch (Exception e){
                e.printStackTrace();
            }
        }

    }
}
以下的的方法调用的线程实现方法都是来自TestThreads。

一:newCachedThreadPool,

创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
public static void callBackThread(){
        ExecutorService cachedThreadPool=Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            cachedThreadPool.execute(new TestThreads(index));
        }
   }

我自己在这里在里面开了10个线程,但其实线程池可以为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。

二、newFixedThreadPool,

创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中
public static void getTaskThread(){
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            final int index = i;
            fixedThreadPool.execute(new TestThreads(index));
        }
    }

我们可以看到,里面只有指定的5个线程在跑,虽然给开了10个,但是由于这run着的5个线程一直死循环(因为我实现方法是个死循环的实现),资源一直没有放,另外5个线程拿不到资源,当然,你可以在自己的实现方法里面不写死循环,这样其他的index也可以拿到数据去run了

三、getSingleThread

创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的

public static void getSingleThread(){
        ExecutorService singleThread=Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            singleThread.execute(new TestThreads(index));
        }
    }

我们可以看到这里的输入结果是依次输出,相当于顺序执行各个任务。这样的方法可以很好的保证线程安全性,但是性能得不到最大的提升。

四、newScheduledThreadPool

创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:

public static void getScheduleThread(){
        ScheduledExecutorService scheduleThread=Executors.newScheduledThreadPool(5);
        for (int i = 0; i < 10; i++) {
            final int index = i;
            scheduleThread.schedule(new TestThreads(index),3, TimeUnit.SECONDS);
        }

    }

在这里我们为了可以看到效果,把实现方法死循环去掉。

变成这个样子:

 @Override
    public void run() {
//        while (true){
            System.out.println("=======2222=====");
            System.out.println(index);
            try{
                Thread.sleep(2000);
            }catch (Exception e){
                e.printStackTrace();
            }
//        }

    }

然后我们可以看到,我们运行的这个线程,延迟3S再执行的。interesting!

猜你喜欢

转载自blog.csdn.net/asd529735325/article/details/83381825
今日推荐