线程同步
JVM线程状态
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
BLOCKED: 表示线程执行在进入(或重新进入)同步代码块或者同步方法前阻塞等待监视器锁(monitor lock),通常是在调用了Object.wait方法后进入BLOCKED状态;
WAITING:处于waiting状态线程通常是调用了以下方法:
1. Object.wait(with no timeout)
2. Thread.join(with no timeout)
3. LockSupport.park
比如一个调用了某个对象的 Object.wait 方法的线程会等待另一个线程调用此对象的Object.notify() 或 Object.notifyAll()。一个调用了 Thread.join 方法的线程会等待指定的线程结束
TIMED_WAITING: 一个正在限时等待另一个线程执行一个动作的线程处于这一状态,通常调用以下方法
Thread.sleep
带时限(timeout)的 Object.wait
带时限(timeout)的 Thread.join
LockSupport.parkNanos
LockSupport.parkUntil
经典的生产者-消费者模型解析以上线程状态:
public class Consumer implements Runnable{
private final Cola cola;
Consumer(Cola cola){
this.cola =cola;
}
@Override
public void run(){
synchronized (cola){
while(cola.colaCount < 1){
try {
cola.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
cola.colaCount --;
cola.drink();
cola.notify();
}
}
}
public class Producer implements Runnable{
private final Cola cola;
Producer(Cola cola){
this.cola = cola;
}
@Override
public void run(){
synchronized (this.cola){
cola.colaCount ++;
System.out.println("Cola be producing...current cola qty is " + cola.colaCount);
cola.notifyAll();
}
}
}
// 测试
public static void main(String[] args) throws InterruptedException {
// monitor lock
Cola cola = new Cola();
Thread consumerA = new Thread(new Consumer(cola));
consumerA.setName("consumerA");
Thread consumerB = new Thread(new Consumer(cola));
consumerB.setName("consumerB");
Thread producer = new Thread(new Producer(cola));
// 启动消费者线程
consumerA.start();
consumerB.start();
Thread.sleep(100);
System.out.println("ConsumerA state is: " + consumerA.getState());
System.out.println("ConsumerB state is: " + consumerB.getState());
// 启动生产者线程
producer.start();
Thread.sleep(100);
System.out.println("ConsumerA state is: " + consumerA.getState());
System.out.println("ConsumerB state is: " + consumerB.getState());
}
运行结果:
ConsumerA state is: WAITING
ConsumerB state is: WAITING
Cola be producing...current cola qty is 1
consumerB be consuming...current cola qty is 0
ConsumerA state is: BLOCKED
ConsumerB state is: TIMED_WAITING
测试代码看出,消费者A,B在分别进入同步方法时由于条件不满足调用了Object.wait方法后线程状态为waiting,此时它们都已释放处于对象Cola监视器锁并处于等待队列(wait set)中。生产者线程增加colaCount后调用notify All方法唤醒wait set中的消费者线程,此时它们将从wait set进入entry set竞争重新进入同步方法,线程状态由waiting -> blocked, 等待调度器调度。同一时刻只有一个消费者线程能到活得资源对象monitor lock,可以看到consumerB拿到了锁并执行sleep方法,线程状态-> time_waiting, consumerA因为没能获取到锁仍然处于blocked状态。
操作系统层面线程状态与JVM线程状态的关系,可以看出JVM线程状态中blocked,waiting和time_waiting本质上是OS中wait状态的细分
线程安全
当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程讲如何交替执行,并且在主线程中不需要做额外的同步或协调,这个类都能表现出正确的行为,那么就程这个类是线程安全的。
线程安全实现策略
1. 线程封闭:线程封闭的对象只能有一个线程拥有,对象被封闭在线程中,并且只能由这个 线程修改
2.只读共享:在没有额外的同步的情况下,共享的只读对象可以由多个线程并发访问,但任何线程都不能修改他。共享的只读对象包括不可变对象和事实不可变对象。
3.线程安全共享:线程安全的对象在其内部实现同步,因此多个线程可以通过对象的共有接口 进行访问而不需要进一步的同步
4.保护对象:被保护的对象只能通过持有特定的锁来访问。保护对象包括封装在其他的线程安全的对象中的对象,以及已发布的并且由某个特定锁保护的对象。
线程中断
- interrupt()只是改变中断状态而已. interrupt()不会中断一个正在运行的线程。这一方法实际上完成的是,给受
阻塞的线程抛出一个中断信号,这样受阻线程就得以退出阻塞的状态。更确切 的说,如果线程被Object.wait,
Thread.join和Thread.sleep三种方法之一阻塞, 那么,它将接收到一个中断异常(InterruptedException),
从而提早地终结被阻塞状态。如果线程没有被阻塞,这时调用interrupt()将不起作用;否则,线程就将得到InterruptedException
异常(该线程必须事先预备好处理此状况),接着逃离阻塞状态
2.interrupted()方法会检查当前线程的中断状态,如果为 "被中断状态 "则改变当前线程为 "非中断状态 "并返回
true,如果为 "非中断状态 "则返回false,它不仅检查当前线程是否为中断状态,而且在保证当前线程状态恢复为非中
断状态,所以它叫 "interrupted ",是说中断的状态已经结束(到非中断状态了)
3.isInterrupted()方法则仅仅检查线程对象对应的线程是否是中断状态,并不改变它的状态.
interrupt 中断操作时,非自身打断需要先检测是否有中断权限,这由jvm的安全机制配置;
如果线程处于sleep, wait, join 等状态,那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常;
如果线程处于I/O阻塞状态,将会抛出ClosedByInterruptException(IOException的子类)异常;
如果线程在Selector上被阻塞,select方法将立即返回;
如果非以上情况,将直接标记 interrupt 状态;
注意:interrupt 操作不会打断所有阻塞,只有上述阻塞情况才在jvm的打断范围内,如处于锁阻塞的线程,不会受 interrupt 中断;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。