Java多线程并发编程的技能主要涵括以下5方面:多线程、线程池、线程锁、并发工具类、并发容器,下面分别详解@mikechen
多线程
多线程
多线程:多个线程并发执行。
同步
Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。
比如:synchronized关键字,在保证结果准确的同时,提高性能,线程安全的优先级高于性能。
并行
多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
并发
通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。
并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。
线程的生命周期
在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态
- 新建状态:当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时仅由JVM为其分配内存,并初始化其成员变量的值
- 就绪状态:当线程对象调用了start()方法之后,该线程处于就绪状态。Java虚拟机会为其创建方法调用栈和程序计数器,等待调度运行
- 运行状态:如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态
- 阻塞状态:当处于运行状态的线程失去所占用资源之后,便进入阻塞状态
- 死亡状态:线程在run()方法执行结束后进入死亡状态。此外,如果线程执行了interrupt()或stop()方法,那么它也会以异常退出的方式进入死亡状态。
线程状态的控制
1.sleep()和yield()和join()
1)sleep()方法作用:让当前线程睡眠一段时间,期间不会释放任何持有的锁。
2) yield()方法作用:让出该线程的时间片给其它线程。线程调用了yield()方法,表示放弃当前获得的CPU时间片,回到就绪状态。最后由线程调度重新选择就绪状态的线程分配CPU资源。
3)join()方法作用:暂停当前线程,等待被调用线程指向结束之后再继续执行。
注意:
1)sleep(long)方法仅释放CPU使用权,锁仍然占用。
2)调用join()的时候,当前线程不会释放掉锁。
2.wait()和notify() 方法和notifyAll()方法
1)wait()方法的作用:让该线程处于等待状态。
2)notify()方法的作用:唤醒处于wait的线程。
3)notifyAll()方法的作用:唤醒所有处于wait状态的线程。
线程池的创建方式
Java提供的7种线程池实现,这 7 种实现方法分别是:
1)Executors.newFixedThreadPool
创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待。
2)Executors.newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
3)Executors.newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
4)Executors.newScheduledThreadPool
创建一个可以执行延迟任务的线程池。
5)Executors.newSingleThreadScheduledExecutor
创建一个单线程的可以执行延迟任务的线程池。
6)Executors.newWorkStealingPool
创建一个抢占式执行的线程池(任务执行顺序不确定),这个是JDK 1.8 添加。
7)ThreadPoolExecutor
手动创建线程池的方式,它创建时最多可以设置 7 个参数。
线程池的核心参数
所谓的线程池的 参数是指在使用 ThreadPoolExecutor 创建线程池时所设置的 7 个参数。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { }
如下图所示:
线程池的执行流程
1、判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。
2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。
3、判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。
Java并发工具包
1.并发工具类
提供了比synchronized更加高级的各种同步结构:包括CountDownLatch、CyclicBarrier、Semaphore等,可以实现更加丰富的多线程操作。
2.并发容器
提供各种线程安全的容器:最常见的ConcurrentHashMap、有序的ConcurrentSkipListMap,实现线程安全的动态数组CopyOnWriteArrayList等。
3.并发队列
各种BlockingQueue的实现:常用的ArrayBlockingQueue、SynchorousQueue或针对特定场景的PriorityBlockingQueue。
4.Executor框架
可以创建各种不同类型的线程池,调度任务运行等,绝大部分情况下,不再需要自己从头实现线程池和任务调度器。
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》