休眠线程
Thread.sleep(毫秒数)
是Thread类中静态方法,用于休眠当前进程。Java线程中有两个延迟方法,其一为sleep,另外的是wait
方法。wait方法是对于Object使用的,要求必须位于对Object锁的代码块中。两者的不同在于,sleep不会释放锁,不会归还所占用的资源。而wait会释放锁,等待其他线程调用Object.notify()方法后,继续竞争变量使用权。
中断线程
Thread.interrupt()方法,在其他线程中向实例化对象发出中断信号。需要注意的是,当线程接收到中断信号并不会中断,只是等同于将状态符更改为中断,但是否处理中断信号是线程内部的事情。可以用thread.isInterrupt()
判断,当前是否为中断状态。
- 中断状态下,线程中调用sleep方法,线程会抛出
InterruptedException
中断异常。同样的如果线程处于sleep的休眠状态中,这个时候收到其他线程发来的中断信号,也会抛出InterruptedException
中断异常。
至于说为什么不提供一个可以直接中断其他线程的方法,其实在Java之前的版本中,终止操作最初是直接暴露给用户。起初,在Thread类中有stop方法,强制线程退出临界区,释放所有锁。但本质上是不安全的强制释放掉线程持有的锁,这样临界区的数据中间状态就会遗留出来,从而造成不可预知的后果。所以在Java更新中删去了stop操作,转而使用interrupt,更像是通知线程该中断了的意味。
线程同步的控制方法
- 临界区:在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后,其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占。
- 互斥量:只有拥有互斥对象的线程才具有访问资源的权限。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出,以便其他线程在获得后得以访问资源。互斥的方法可以在不同应用程序的线程之间实现对资源的安全共享。
- 信号量:信号允许多个线程同时使用共享资源,但是需要限制在同一时刻访问此资源的最大线程数目。
- 事件:对象通过通知操作的方式来保持线程的同步。
锁池和等待池
Java中每个对象都有两个池
- 锁池:当一个对象正在被某个线程占用锁,这个时候所有其他需要访问该对象锁的线程,因为得不到锁,所以这些线程都会进入该对象的锁池中。
- 等待池:当一个线程调用锁对象的wait方法,则会释放该对象的锁,进入该对象的等待池,等待notify方法唤醒。
等待线程结束
Thread类中提供了thread.join()
方法,能够使主线程进入等待池,并等待thread线程执行完毕后才会被唤醒。并不影响同一时刻处在运行状态的其他线程。这样就使得
a.start();
a.join
b.start();
原本线程a和线程b是并发执行的,谁先谁后是随机的。但在加入join方法后,线程b的执行就必须等到线程a结束后。
PS.单例模式
在基于同一个时刻一个类,只允许有一个实例化对象存在。
public class SingleObject {
//静态变量保证该类实例化的所有对象拥有同一个内存
private static SingleObject instance = null;
//让构造函数为 private,这样除了使用类内方法实例化外,没有其他实例化途径
private SingleObject(){}
//获取唯一可用的对象
public static SingleObject getInstance(){
if(instance == null){
instance = new SingleObject();
}
return instance;
}
}