为什么要用线程池

1.为什么要用线程池
多线程的情况下确实可以最大限度发挥多核处理器的计算能力,提高系统的吞吐量和性能。但是如果随意使用线程,对系统的性能反而有不利影响。

比如说

 new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

这样直接创建线程,在简单应用里面看起来没有问题,创建了一个线程,并且在run()方法结束后自动回收该线程。但是如果在真实系统里面,可能会由于业务情况,开启了很多线程,当线程数量多大时,反而会耗尽cpu和内存资源。

比如说,创建和销毁线程也需要时间,如果创建和销毁的时间远大于线程执行的时间,反而得不偿失。
其次线程也需要占用内存空间,大量的线程会抢占宝贵的内存资源,可能会导致out of memory异常。
且大量的线程回收也会给GC带来很大的压力,延长GC的停顿时间。

比如说 开启10000000个线程的时候

 for (int i = 0; i <10000000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }

Exception in thread “main” java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:717)
at demo4.ThreadDemo.main(ThreadDemo.java:17)

所以千万要警惕这种情况的发生

最后,大量的线程也会抢占cpu的资源,cpu不停的在各个线程上下文切换中,反而没有时间去处理线程运行的时候该处理的任务。

因此,为了避免频繁的创建和销毁线程,让创建的线程进行复用,就有了线程池的概念。
线程池里会维护一部分活跃线程,如果有需要,就去线程池里取线程使用,用完即归还到线程池里,免去了创建和销毁线程的开销,且线程池也会线程的数量有一定的限制。

比如说刚刚的代码,通过使用线程池来构建线程

ExecutorService executorService= Executors.newFixedThreadPool(10);
        for (int i = 0; i <10000000; i++) {
           Thread t= new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("启动线程");
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });

            executorService.submit(t);
        }

    }

可以看到,将不会再产生out of memory的错误,因为每次将只有10个线程在启用,其余的放在线程池内的任务队列里面。
这是使用线程池的好处之一。

但是线程池也分很多种,要视情况使用,newFixedThreadPool内部的任务队列是无界队列,如果放到的任务过多,最终也会导致内存不足。

你可能感兴趣的:(多线程并发,并发编程)