• java多线程


    创建多线程时不推荐使用Executors来创建线程次,推荐手动创建线程池(ThreadPoolExecytor),源码如下:

    import com.google.common.util.concurrent.ThreadFactoryBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import java.util.concurrent.*;
     
    @Configuration
    public class ThreadPoolConfig {
     
        @Bean(value = "myThreadPool")
        public ExecutorService buildMyThreadPool(){
            // nameFormat- 一个String.format(String, Object...)兼容的格式字符串,将作为单个参数提供唯一的整数(0,1等)
            // 此整数对于ThreadFactory的构建实例是唯一的,并将按顺序分配。
            // 例如,"rpc-pool-%d"会产生像线程名称 "rpc-pool-0","rpc-pool-1","rpc-pool-2"
            ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("my-thread-%d").build();
     
            ExecutorService executorService = new ThreadPoolExecutor(
                    18
                    ,30
                    ,0
                    ,TimeUnit.MILLISECONDS
                    ,new ArrayBlockingQueue<>(1000)
                    ,threadFactory
                    ,new ThreadPoolExecutor.CallerRunsPolicy()
            );
            return executorService;
        }
    }

    首先这个方法的返回值是java.util.concurrent.ExecutorService ,查看源码该接口继承Executor,Executor接口只有一个方法:

     回到此配置类代码,可以看出具体实现是调用java.util.concurrent.ThreadPoolExecutor,查看源码它继承抽象类AbstractExecutorService,而AbstractExecutorService实现ExecutorService接口,所以可以调用execute方法。

    @Resource(name = "myThreadPool")
    private ExecutorService myThreadPool;
     
    //在某方法中执行...
    myThreadPool.execute(new Runnable() {
        @Override
        public void run() {
            //业务代码
        }
    });

    查看execute()方法的源码:

     再看ThreadPoolExecutor的配置,源码中的有参构造如下:

     

    重点在BlockingQueueRejectedExecutionHandler

    线程池处理任务的优先级

    BlockingQueue(线程池使用的缓冲队列)

     缓冲队列详解

           首先要理解一点,如果运行的线程等于或多于 corePoolSize,则Executor始终首选将请求加入队列,而不添加新的线程;如果无法将请求加入队列,则创建新的线程。

        直接提交 SynchronousQueue

           该队列是将任务直接提交给线程而不保存它们。SynchronousQueue线程安全的Queue,可以存放若干任务(但只允许一个任务在等待),每个线程插入必须等待另一个线程移除,也就是说A任务进入队列,B任务必须等A任务被移除之后才能进入队列,否则执行异常策略。你来一个我扔一个,所以SynchronousQueue没有内部容量。如:

         无界队列  LinkedBlockingQueue

           无界队列会使在所有核心线程都在忙时,新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize。(因此,maximumPoolSize的值无意义,不会有新线程被创建,都在排队)。如果未指定容量,则它等于 Integer.MAX_VALUE。如果设置queue预定义容量,则当核心线程忙碌时,新任务会在队列中等待,超过预定义容量就会执行异常策略。你来一个我接一个,直到我容不下你了。FIFO,先进先出。如:

         有界队列  ArrayBlockingQueue

           操作模式跟LinkedBlockingQueue查不多,但必须为其设置容量。new ArrayBlockingQueue<Runnable>(Integer.MAX_VALUE) 跟 new LinkedBlockingQueue(Integer.MAX_VALUE)效果一样。LinkedBlockingQueue底层是链表结构,ArrayBlockingQueue底层是数组结构。你来一个我接一个,直到我容不下你了。FIFO,先进先出。

        总结

    RejectedExecutionHandler(拒绝策略)

    表示任务(队列和最大线程数)已经饱和了,但还有线程进入,只好拒绝接受,并根据配置的不同策略进行不同的处理。

     

  • 相关阅读:
    BZOJ 3669 & luogu 2387 魔法森林
    caioj 2064 & POJ 1741 & CH 0x40数据结构进阶(0x45 点分治)例题1:树
    caioj 2063& CH 0x40数据结构进阶(0x44 分块)例题4:小Z的袜子
    BZOJ 2154: Crash的数字表格
    追查坏牛奶(最大流)
    [JLOI2014]松鼠的新家
    [HAOI2015]树上操作
    [NOI2015]软件包管理器(树链刨分)
    [JSOI2008]球形空间产生器(高斯消元)
    [ZJOI2008]树的统计(树链刨分)
  • 原文地址:https://www.cnblogs.com/dashazia/p/12204793.html
Copyright © 2020-2023  润新知