首先我们需要知道互斥锁的概念, 是能够达到互斥访问目的的锁. 那么如果对临界资源加上互斥锁, 当一个线程在访问该临界资源的时候, 其他线程只能等待.
在Java中, 每个对象都拥有锁标记(monitor), 也称为监视器. 多线程同时访问某一对象的时候, 只有获取了该对象所的线程才能访问.
在Java中, 可以使用synchronized关键字来修饰一个方法或者一个代码块, 当某个线程调用被修饰的方法或者代码块时, 这个线程便获得了这个对象的锁, 其余线程就无法访问. 只有等待这个线程退出临界区, 才会释放该对象的锁, 其余线程才能访问.
import java.util.ArrayList;
class MyArrayList {
private ArrayList<Integer> arrayList = new ArrayList<>();
synchronized void insert(Thread thread) {
for(int i = 0; i < 10; i++) {
System.out.println("thread " + thread.getName() + " : insert " + i);
arrayList.add(i);
}
}
}
public class Test {
public static void main(String[] args) {
final var myArrayList = new MyArrayList();
new Thread(() -> myArrayList.insert(Thread.currentThread())).start();
new Thread(() -> myArrayList.insert(Thread.currentThread())).start();
}
}
如果我们对含有synchronized方法或者代码段的class进行反编译, 就可以从字节码中看到monitorenter和monitorexit两条指令. 前者会让对象锁计数加一, 后者减一. 类似于操作系统中的PV原语.
值得注意的是线程的block和wait状态是两个完全不同的状态.
由此可见, block态和wait态最大的区别在于前者是有JVM调度, 而后者是在代码中主动调用并调度的.
值得注意的是: