Java_多线程
ch16_多线程
github源码参考: github jackaroo2020
16.1 线程概述
1.进程三个特性
- 独立性:每个进程拥有自己独立的私有地址空间。
- 动态性:是一个正在系统中活动的指令集合。
- 并发性:可以在单个处理器上并发执行,多个进程之间不会相互影响。(并发指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得宏观上具有多个进程同时执行的效果。
2.操作系统可以执行多个任务,每个任务就是进程;进程可以同时执行多个任务,每个任务就是线程。
3.多线程优点
- 进程不可以共享内存,但线程之间共享内存非常容易。
- 系统创建进程时需要为该进程重新分配系统资源,但创建线程则代价小得多,因此使用多线程实现多任务并发比多进程效率高。
- java语言内置多线程功能支持,简化编程。
16.2 多线程的创建和启动
1.继承Thread类创建线程类
2.实现Runable接口创建线程类
3.使用Callable和Future创建线程
4.创建三种方式的对比
notice:
- java程序运行默认的主线程,main方法的方法体就是主线程的线程执行体。
- 使用继承Thread类的方法来创建线程类时,多个线程之间无法共享线程类的实例变量。
- 一般推荐使用实现Runable接口,Callable接口的方式来创建多线程。
16.3 线程的生命周期
1.新建(new)和就绪状态(start)
2.运行(run) 和阻塞状态
3.线程死亡
notice:
- 不要对处于死亡状态的线程调用start()方法,否则会引发IllegalThreadStateException异常。
16.4 控制线程
1.join线程
2.后台线程
3.线程睡眠
4.线程让步
5.改变线程的优先级
16.5 线程同步
1.线程安全问题
2.同步代码块
3.同步方法
4.同步锁(lock)
5.死锁
16.6 线程通信
1.传统的线程通信 synchronized wait() notify() notifyAll()
2.使用Condition控制线程通信 Lock await() signal() signalAll()
3.使用阻塞队列控制线程通信
16.7 线程组与未处理的异常
16.8 线程池
- newCachedThreadPool()
- newFixedThreadPool()
- newSingleThreadExecutor()
- newScheduledThreadpool(int corePoolSize)
- newSingleThreadScheduledExecutor()
- newWorkStealingPool()
调用线程池执行线程任务的步骤:
1)调用Executor类的静态工厂方法穿件一个ExecutorService对象,该对象代表一个线程池。
2)创建Runnable实现类或Callable实现类的实例,作为线程执行的任务。
3)调用ExecutorService对象的submit()方法来提交Runnable实例或Callable实例。
4)当不想提交任务任务时,调用ExecutorService对象的shutdown()方法来关闭线程池。
16.9 线程相关类
1)ThreadLocal类
就是为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本;而不会和其他线程的副本冲突。
ThreadLocal并不能替代同步机制,两者面向的问题领域不同。同步机制是 为了同步多个线程对相同资源的并发访问,是多个线程之间进行通信的有效方式;
ThreadLocal是为了隔离多个线程的数据共享,从根本上避免多个线程之间对共享资源(变量)的竞争,也就不需要对多个线程进行同步了。
建议:如果多个线程之间需要共享资源,以达到线程之间的通信功能,就使用同步机制;
如果需要隔离多个线程之间的共享冲突,则可以使用ThreadLocal。
2)包装线程不安全的集合类
Collections提供的类方法吧这些集合可以包装成线程安全的集合。
HashMap m = Collections.synchronizedMap(new HashMap());
3)线程安全的集合类
- 以Concurent开头的集合类,如ConcurrentHashMap、ConcurrentLinkedQueue
- 以CopyOnWrite开头的集合类,如CopyOnWriteArrayList(适合用在读取操作远远大于写入操作的场景中,如缓存等)、CopyOnwriteArraySet