系列文章目录
多线程并发编程系列
文章目录
- 系列文章目录
- 一、进程、线程、并发、并行、的基础概念
- 二、什么时候考虑引入多线程
- 三、多线程使用的注意事项
- 1线程不是开的越多越好
- 2 多线程带来的线程安全问题
- 总结
提示:以下是本篇文章正文内容
一、进程、线程、并发、并行、的基础概念
进程:进程是程序在执行过程中分配和管理资源的基本单位。
线程: 线程是cpu调度和分配资源的最小单位。
并发:并发是针对单个cpu来说的,多个线程轮流在一个cpu上执行任务,当时间片用完后,会切换到下一个线程使用,这也是我们常说的线程的上下文切换。实际上多个线程是依次执行任务的,并且速度非常快,看上去像是多个线程一起执行一样。我们可以这样形容并发,在单个cpu上的一个时间段内,线程依次执行。
并行:并行是针对多核来说的,可以把多核说成多个cpu,在多核环境中一个cpu对应一个线程,比如8核,我们如果开了8个线程的话,每个线程分配一个cpu,这时他们是同时执行任务的,在一个时间点上齐头并进。如果有20个线程呢,这时当8个线程首先占好位置后,剩下的12个线程要等待前面线程的时间片用完才能轮到他们。所以我们可以这样说,如果看前8个线程,他们是并行的,因为是在同一个时间点启动的。但是看20个线程呢,他们是并发的,他们会在一段时间后才能执行完成。
所以我们java项目部署的应用服务器有 4核、8核、16、32、64核的说法,核数越多,我们可以开的线程也就越多,但是也不能开过多的线程,否则单个线程的任务执行时间也会变长。一般我们开的线程是大于核心数的,这样才能充分利用多核的优势。
二、什么时候考虑引入多线程
我们先看多线程的作用:异步、 缩短长任务时间
举个例子,包工头指挥工人干活, 1个人需要300天,那么理论上10个人只要30天, 100个人只要3天,而包工头自己可以做其他的事,直接向老板反馈目前进度(异步),而工人还在干活(多线程缩短长任务时间)这样就把一个长任务拆解成数十个小任务,时间就缩短了10倍。
一般我们耗时较长的需求就可以考虑加入多线程了,比如导入导出、复杂的耗时计算、或者需要先返回结果的需求,让任务在后台慢慢处理,先把处理中的状态返回给前端。
三、多线程使用的注意事项
1线程不是开的越多越好
对于一个服务器而言,能开辟的线程总数是有限(受限于cpu的性能、虚拟空间的大小、栈 的大小的限制、操作系统的位数、什么操作系统)一般的小型系统设置几百就够了,通过集群的方式能处理些并发量不高的功能模块。
对于线程池而言,因为线程属于一种宝贵资源,所以能少开尽量少开,比如使用ThreadPoolExecutor线程池设置的核心线程数是常驻线程,并不会进行销毁,所以线程池的核心线程要合理设置否则也会给系统带来负担。对于不经常调用的接口,可以利用
static {
executor.allowCoreThreadTimeOut(true);
}
把核心线程设置超时时间自动销毁掉。
2 多线程带来的线程安全问题
当多个线程对同一共享资源并发进行读写的时候,就有可能发生线程安全问题,对于方法内的资源是每个线程独有的,不需要考虑,但是方法外的比如说成员变量 new一个arrayList,就需要通过加锁来控制同时只有一个线程来访问。我们引申下,数据库中的数据同样也是属于共享资源,mysql通过数据库的共享锁(S)、排它锁锁(X)、意向共享锁(IS)、意向排他锁(IX)来保证资源的安全问题。
需要注意的是如果是分布式环境,需要考虑你的业务是不是需要保证就算有多个节点,同一个方法也只允许一个线程进入。普通的锁是JVM层面的锁,只能保证当前机器中的同一个方法在同一时间只能被一个线程访问,他保证不了其他机器部署的相同应用的同一个方法的安全性。我们需要借助分布式锁来保证就算有多台机器,同一时间只有一个线程来执行某一个方法。
总结
这篇文章主要讲的是多线程并发编程的应用层面的理解使用,后面的文章会把上面介绍的点,详细的进行介绍