线程终止
1.run方法正常退出,线程自然终止
2.因为一个没有捕获的异常终止了run方法,线程意外终止
线程中断
除了已经废弃的stop方法,没有办法可以强制线程终止.为什么stop方法要废弃?
因为stop方法可以终止所有未结束的方法,包括run方法,线程终止会立马释放被它锁定的所有对象的锁,会导致对象的状态不一致,所以一个线程要终止另一个线程,无法知道什么时候调用stop方法是安全的.
同样的,suspend方法也被废弃了,因为如果suspend方法挂起了一个持有锁的线程,那么线程恢复之前这个锁是不可用的,调用suspend方法的线程试图获得这个锁,程序就进入了死锁:被挂起的线程等着回复,而将他挂起的线程又等待获得锁.(简单的说就是,同一个线程同时将他挂起,又想获得锁)
守护线程
可以通过setDaem方法将一个线程转化为守护线程(必须在线程启动前使用),守护线程的作用就是为其他线程提供服务的,例如计时器线程,清空过失缓存线程.如果程序中只有守护线程,那么程序也就没有了运行的意义了.
锁对象
-
ReentrantLock
通过构造方法有两种构建方式:一种是非公平锁,一种是公平锁 ,公平锁倾向于等待时间最长的线程,但是可能会严重影响性能,因此默认情况下不要求锁是公平的.
注意:一定要将unlock操作放到finally中,如果在临界区抛出异常没有释放锁,其他线程将永远阻塞.
-
条件对象Condition
当进入临界区却发现必须满足条件才能执行,所以引入了条件对象,当前线程要暂停并放弃锁,调用await方法,线程进入条件等待集,当满足条件后调用signalAll方法,从等待集中移除,重新激活线程.
只有当前线程拥有条件锁时才能在这个条件上调用awati,signalAll方法.
-
Synchronized关键字
在Java1.0之后,每个对象都有一个内部锁,如果方法声明时有Synchronized关键字,要调用这个方法要先获得内部对象锁.
-
volatile字段
如果只是为了读写一两个字段而使用同步锁,开销太大.volatil为同步访问提供了一种免锁机制,如果对volatile修饰的变量进行了修改,这个修改对读取这个变量的所有其他线程都可见,增加了线程之间的可见性!
volatile关键字并没有保证原子性!
实现多线程的方式:
1.实现Runnable接口
2.继承Thread类
3.实现Callable接口
4.实现Future接口
Callable接口的Call方法有返回值,返回值类型与类型参数相同
可以使用futureTask来执行callable
FutureTask<Integer> futureTask = new FutureTask<>(new Demo3());
Thread thread = new Thread(futureTask);
线程池与任务
池是一种非常优秀的设计思想,通过建立池可以有效的利用系统资源,节约系统性能.
-
使用线程池的好处
降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控
执行器
Executors类通过静态工厂来构造线程池,工厂方法有:
- newCachedThreadPool:必要时创建新线程,空闲线程会存在60s
- newFixedThreadPool:池中包含固定数目的线程,空闲线程会一直保留.
任务提交给线程池
将Runnable或者Callable对象提交给ExecutorSer,使用submit方法来进行提交.