在前边 Java高并发(四)——ThreadPool,线程复用 中我们学习了ThreadPool,但是在那篇中我们在create Thread pool的时候,由于我安装了阿里的开发规范插件,一直在警告我。这篇我们先看下警告,然后再看下并行开发中常见的模式。
** 一,如何更合理的创建ThreadPool:**
1,警告:手动创建线程池,效果会更好哦!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 1//1,这样创建线程
2ExecutorService es = Executors.newFixedThreadPool(size);
3/**
4*
5阿里警告全文:
6线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors各个方法的弊端:
71)newFixedThreadPool和newSingleThreadExecutor:
8 主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
92)newCachedThreadPool和newScheduledThreadPool:
10 主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。
11
12Positive example 1:
13 //org.apache.commons.lang3.concurrent.BasicThreadFactory
14 ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
15 new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
16
17
18
19Positive example 2:
20 ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
21 .setNameFormat("demo-pool-%d").build();
22
23 //Common Thread Pool
24 ExecutorService pool = new ThreadPoolExecutor(5, 200,
25 0L, TimeUnit.MILLISECONDS,
26 new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
27
28 pool.execute(()-> System.out.println(Thread.currentThread().getName()));
29 pool.shutdown();//gracefully shutdown
30
31
32
33Positive example 3:
34 <bean id="userThreadPool"
35 class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
36 <property name="corePoolSize" value="10" />
37 <property name="maxPoolSize" value="100" />
38 <property name="queueCapacity" value="2000" />
39
40 <property name="threadFactory" value= threadFactory />
41 <property name="rejectedExecutionHandler">
42 <ref local="rejectedExecutionHandler" />
43 </property>
44 </bean>
45 //in code
46 userThreadPool.execute(thread);
47**/
48
2,警告:要使用带有ThreadFactory参数的ThreadPoolExecutor构造方法哦,这样你就可以方便的设置线程名字啦。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 1//2,这样创建线程
2ExecutorService executorService = new ThreadPoolExecutor(size,size,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
3
4/**
5 *
6创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。创建线程池的时候请使用带ThreadFactory的构造函数,并且提供自定义ThreadFactory实现或者使用第三方实现。
7
8 ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
9 .setNameFormat("demo-pool-%d").build();
10 ExecutorService singleThreadPool = new ThreadPoolExecutor(1, 1,
11 0L, TimeUnit.MILLISECONDS,
12 new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
13
14 singleThreadPool.execute(()-> System.out.println(Thread.currentThread().getName()));
15 singleThreadPool.shutdown();
16
17
18
19 public class TimerTaskThread extends Thread {
20 public TimerTaskThread(){
21 super.setName("TimerTaskThread"); …
22 }
23**/
24
** 二,多线程常见的并行模式:**
1,单例模式 | 无论懒汉模式、恶汉模式,单例模式都需要多线程并发的场景下,保证单个对象的创建,这里可以阅读:https://www.cnblogs.com/zhaoyan001/p/6365064.html |
2,不变模式 | 一种不改变对象,依靠对象的不变性,确保其在多线程并发场景下内部状态的一致性正确性。 通过:a,去除setter方法及修改自身属性的方法; b,将所有属性设置为私有,并用final标记,确保其不可修改; c,确保没有子类可以重载修改它的行为; d,有一个可以创建完整对象的构造函数。 例如:元数据的包装类,String、Boolean、Byte、Integer等. |
3,生产者-消费者模式 | 两类线程通过共享内存缓冲区进行通信,进而达到两类线程的解耦,相互独立,只和共享内存缓冲区剩余空间及存储资源有关。这里可以阅读:https://www.cnblogs.com/chentingk/p/6497107.html |
4,Future模式 | 多线程结果异步调用,提高性能,这里不再赘述,看 Java高并发(七)——Future模式 |
5,并行流水线 | 通过将任务拆解为多个步骤,用不同的线程处理不同的步骤,像现实生活中的生产流水线一样。例如数据分析:可以2个线程收集数据,5个线程分析数据、2个线程预警有问题数据…… |
6,并行搜索 | 将搜索范围进行有效的拆分,使用多个线程,搜索不同的范围,一个线程搜索到结果即可返回停止。 |
7,并行排序 | 将排序的任务想办法如何分割,然后使用多线程进行处理不同任务。其实挺难的,不过是一种思路,可以考虑,这里可以阅读(冒泡排序中的奇偶交换排序):https://blog.csdn.net/qq_37142346/article/details/79573440 |
8,并行算法 | 例如当今比较火的AI,如何将算法在高效的处理上实现并行处理,将又一次提高性能。例如庞大矩阵的四则运算等,这里还需要更多的学习,提出一种思路而已。 |
9,网络多线程 | NIO,Reactor模式等。东西比较多,看我的Netty系列即可。Netty将多线程运用的非常棒。 |
1 | 1 |
好,这里进行了前边文章的补充,和一些多线程使用中一些模式一些思路的小结,在我们开发编码,我们可以参考,善于站在巨人的肩膀上,善于思考,善于将前人的东西转化为自己的。继续……