目录

1.为什么使用线程池?

反复创建线程开销大,可以复用线程池
过多的线程会占用太多的内存

解决以上问题的方法:

  • 用少量的线程,避免内存占用过多
  • 让这部分线程都保持工作,且反复执行任务,避免生命周期的损耗

2.线程池的好处:

加快响应速度,提高用户体验
合理利用cpu内存
统一管理

3.线程池使用的场合

服务器接受大量请求时,使用线程池技术是非常合适的,它可以大大减少线程的创建和销毁次数,提高服务器的工作效率。在实际开发中,如果创建5个以上 的线程,那么就可以使用线程池来管理线程。

4.创建和停止线程

线程池构造方法的参数?
线程池应该手动创建和自动创建那个更好?
线程池里的线程数量设置未多少合适?
停止线程的正确方法?

线程池构造函数的参数:

corepoolsize: 核心线程数
线程池在完成初始化后,默认情况下,线程池中并没有任何线程,会等到有任务到来时再去创建新的线程去执行任务。
maxpoolsize:在核心线程的基础上,额外增加的线程数的上限。

根据图可知添加线程的规则:

1.如果线程数小于corepoolsize,即使其他工作线程处于空闲状态,也会创建一个新线程来运行任务。
2.如果线程数等于或大于corepoolsize但少于maximumpoolsize,则将任务放入队列。
3.如果线程池已满,并且线程数小于maxpoolsize,则创建一个新线程来运行任务。
4.如果队列已满,并且线程数大于或等于maxpoolszie,则参数拒绝该任务。

添加线程判断顺序:corepoolsize——workqueue——maxpoolsize

比如线程池的核心线程是5个,最大线程池大小为10个,队列为50个。
则线程池的请求最多会创建5个,然后任务将被添加到队列中,直到达到50。队列已满时,将创建最新的线程maxpoolsize,最多达到10个,如果再来任务就直接拒绝。

keepalivetime:如果线程池当前的线程数多于corepoolsize,那么如果多余的线程空闲时间超过keepalivetime,那么就会终止。

threadfactory:
默认使用executors.defaultthreadfactory()
创建出来的线程都在同一个线程组。
如果自己指定threadfactory,那么就可以改变线程名、线程组、优先级、是否是守护线程等等。

常见的3中队列类型:
直接交接:synchronousqueue
无界队列:linkedblockingqueue
有界队列:arrayblockingqueue

线程池应该手动创建和自动创建那个更好?

手动创建好,因为这样可以明确线程池的运行规则和避开资源浪费的风险。

  • newfixedthreadpool:容易造成大量内存占用,可能导致dom
    public class fixedthreadpooltest  {
        public static void main(string[] args) {
            executorservice executorservice = executors.newfixedthreadpool(4);
            for (int i = 0; i < 500; i++) {
                executorservice.execute(new task());
            }
        }
    }
    class task implements runnable{
    
        @override
        public void run() {
            try {
                thread.sleep(500);
            } catch (interruptedexception e) {
                e.printstacktrace();
            }
            system.out.println(thread.currentthread().getname());
        }
    }
    
  • newsinglethreadexecutor:当请求堆积的时候,可能会占用大量内存。
    //演示fixedthreadpool出错
    public class fixedthreadpooloom {
        private static executorservice executorservice = executors.newfixedthreadpool(1);
    
        public static void main(string[] args) {
            for (int i = 0; i < integer.max_value; i++) {
                executorservice.execute(new subthread());
            }
        }
    }
    class subthread implements runnable{
    
        @override
        public void run() {
            try {
                thread.sleep(10000000);
            } catch (interruptedexception e) {
                e.printstacktrace();
            }
        }
    }
    
  • newcachedthreadpool:弊端在于第二个参数maximumpoolsize被设置为了integer.max_value,这可能会创建数量非常多的线程,甚至导致dom
  • newscheduledthreadpool:原因和newcachedthreadpool一样

常见的线程池:

fixedthreadpool

cachedthreadpool:可缓存线程池,具有自动回收多余线程的功能

scheduledthreadpool:支持定时及周期性任务执行的线程池
singlethreadexecutor:单线程的线程池只会用唯一的工作线程来执行任务
原理和fixedthreadpool一样,但是线程数量被设为1

四种线程池的构造方法的参数:

阻塞队列分析:

5.停止线程池的方法

  • shutdown:只是将线程池的状态设置为 shutdown 状态,但任务并没有中断,还是会继续执行下去。此时线程池不会接受新的任务,只是将原有的任务执行结束。
  • shutdownnow:将线程池的状态设置为stop,正在执行的任务会停止,没被执行的任务会被返回。
  • isshutdown:当调用shutdown()或shutdownnow()方法后返回为true,否则返回为false。
  • isterminated:线程任务全部执行完返回true
  • awaitterminated:有两个参数,第一个是long类型的数值,第二个是时间类型timeunit,用于设置阻塞时间。它是一个阻塞的方法,若线程池一直运行则会一直阻塞,直到线程池关闭返回true,或阻塞时间超过你设置的这个时间,则返回false。此方法必须放在shutdown()方法之后,否则一直在阻塞,或超过设置的阻塞时间返回false。
//演示关闭线程池
public class shutdown {
    public static void main(string[] args) throws interruptedexception {
        executorservice executorservice = executors.newfixedthreadpool(10);
        for (int i = 0; i < 500; i++) {
            executorservice.execute(new shutdowntask());
        }
        thread.sleep(1500);
//        executorservice.shutdown();
//        system.out.println(executorservice.isshutdown());
        executorservice.awaittermination(3l, timeunit.seconds);
    }
}
class shutdowntask implements runnable{

    @override
    public void run() {
        try {
            thread.sleep(500);
            system.out.println(thread.currentthread().getname());
        } catch (interruptedexception e) {
            e.printstacktrace();
        }
    }
}

6.暂停和恢复线程池

//暂停线程池
 pauseablethreadpool.pause();
 //恢复线程池
 pauseablethreadpool.resume();

代码实现:

//演示每个任务执行前后放钩子函数
public class pauseablethreadpool extends threadpoolexecutor {
    private final reentrantlock lock = new reentrantlock();
    private condition unpaused = lock.newcondition();
    private boolean ispaused;

    public pauseablethreadpool(int corepoolsize, int maximumpoolsize, long keepalivetime, timeunit unit, blockingqueue<runnable> workqueue) {
        super(corepoolsize, maximumpoolsize, keepalivetime, unit, workqueue);
    }

    public pauseablethreadpool(int corepoolsize, int maximumpoolsize, long keepalivetime, timeunit unit, blockingqueue<runnable> workqueue, threadfactory threadfactory) {
        super(corepoolsize, maximumpoolsize, keepalivetime, unit, workqueue, threadfactory);
    }

    public pauseablethreadpool(int corepoolsize, int maximumpoolsize, long keepalivetime, timeunit unit, blockingqueue<runnable> workqueue, rejectedexecutionhandler handler) {
        super(corepoolsize, maximumpoolsize, keepalivetime, unit, workqueue, handler);
    }

    public pauseablethreadpool(int corepoolsize, int maximumpoolsize, long keepalivetime, timeunit unit, blockingqueue<runnable> workqueue, threadfactory threadfactory, rejectedexecutionhandler handler) {
        super(corepoolsize, maximumpoolsize, keepalivetime, unit, workqueue, threadfactory, handler);
    }

    @override
    protected void beforeexecute(thread t, runnable r) {
        super.beforeexecute(t, r);
        lock.lock();
        try {
            while (ispaused) {
                unpaused.await();
            }
        } catch (interruptedexception e) {
            e.printstacktrace();
        } finally {
            lock.unlock();
        }
    }

    private void pause() {
        lock.lock();
        try {
            ispaused = true;
        } finally {
            lock.unlock();
        }
    }

    public void resume() {
        lock.lock();
        try {
            ispaused = false;
            unpaused.signalall();
        } finally {
            lock.unlock();
        }
    }

    public static void main(string[] args) throws interruptedexception {
        pauseablethreadpool pauseablethreadpool = new pauseablethreadpool(10, 20, 10l, timeunit.seconds, new linkedblockingqueue<>());
        runnable runnable = new runnable() {
            @override
            public void run() {
                system.out.println("我被执行");
                try {
                    thread.sleep(10);
                } catch (interruptedexception e) {
                    e.printstacktrace();
                }
            }
        };
        for (int i = 0; i < 10000; i++) {
            pauseablethreadpool.execute(runnable);
        }
        thread.sleep(1500);
        pauseablethreadpool.pause();
        system.out.println("线程池被暂停了");
        thread.sleep(1500);
        pauseablethreadpool.resume();
        system.out.println("线程池被恢复了");

    }
}

实现原理及源码分析:
线程池的组成部分:

  • 线程池管理器
  • 工作线程
  • 任务队列
  • 任务接口(task)

到此这篇关于java线程池由浅入深掌握到精通的文章就介绍到这了,更多相关java 线程池内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!