Synchronized
synchronized包含monitor enter, monitor exit 2个JVM指令(遵循happens-before原则), 执行monitor exit之前必须存在monitor enter指令.
由于每个对象与一个monitor产生关联, 线程执行monitor enter时, 就会获取monitor的lock, monitor中存在计数器, 用于记录当前lock被获取的情况, 当线程已经获取了lock, 再次进行线程重入, lock往上自增.
与之相反, 当线程执行到monitor exit时, 对应的monitor计数器就会自减
- this monitor: synchronized修饰的对象是this
public synchronized void test(){
//...
}
//A实现Runnable接口
A a = new A();
new Thread(a).start();
new Thread(a).start();
- class monitor: synchronized修饰的对象是class
public synchronized static void test() {
//...
}
或者
public void test() {
synchronized(A.class) {
//...
}
}
//A实现Runnable接口
A a1 = new A();
A a2 = new A();
//此时a1 与a2 共用一个class monitor
new Thread(a1).start();
new Thread(a2).start();
Thread API
sleep, yield, wait, notify/notifyAll, interrupt, interrupted, join
- sleep
Thread.sleep(), 线程休眠, 但休眠不会释放锁资源, 线程从running => block的状态切换, 可以使用thread.interrupt中断睡眠 - yield
Thread.yield(), 当前线程放弃CPU资源(CPU资源不紧张, 将忽略), 线程从running => runnable的状态切换, 因此不能使用interrupt中断处于runnable状态的线程 - wait
线程放弃锁资源, 并进入与锁关联的waitSet集合, 状态变化: Running => Blocked, 可以设定
object.wait()等价于object.wait(0), 表示阻塞时间是永远
注: wait必须在同步代码内. waitSet依赖于锁资源, 没有在同步代码内, 抛出IllegalMonitorStateException
wait与sleep相似点:
1. 都能使线程阻塞
2. 都是可中断
3. wait属于Object, sleep属于Thread
4. wait需要在同步代码块中, sleep不需要
5. wait状态下, 将会是否锁资源, sleep不会释放锁资源
6. sleep执行一段自动退出阻塞状态, wait(long)一样.
- notify/notifyAll
notify随机唤醒waitSet集合中某一线程, notifyAll唤醒waitSet集合中所有的线程, 被唤醒的线程重新争抢锁资源, 争抢到之后, 接着刚才wait的地方往后执行
注: notify必须在同步代码内. waitSet依赖于锁资源, 没有在同步代码内, 抛出IllegalMonitorStateException - interrupt
打断当前线程阻塞状态, 可使用interrupt进行中断的方法如下:
object.wait(), object(long), Thread.sleep(long), thread.join(), Selector.wakeup()
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
//设置中断标识, interrupt0属于native方法
interrupt0();
b.interrupt(this);
return;
}
}
interrupt0();
}
当线程使用休眠方法进入阻塞状态后, 使用thread.interrupt设置中断标志, 随后线程被中断, 抛出InterruptedException, 线程终止运行
isInterrupt: 用于判断线程是否被中断, 从下面源码看出, 判断线程是否被中断, 不会清除中断标志
public boolean isInterrupted() {
//native方法, clearInterrupted设置为false
return isInterrupted(false);
}
思考: wait, sleep, yield被中断后会不会清除中断标志
/**
* 测试
* @author regotto
*/
public class InterruptTest {
private static final Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("1.isInterrupted: " + Thread.currentThread().isInterrupted());
lock.wait();
} catch (InterruptedException e) {
System.out.println("2.isInterrupted: " + Thread.currentThread().isInterrupted());
}