执行线程
// 第一种:实现Runnable new Thread(new Runnable() { @Override public void run() { // ... } }).start(); // 第二种:继承Thread new Thread() { @Override public void run() { // ... } }.start();
synchronized
如果是 static 方法,锁的是 class 对象,在字节码中无法看到它的锁,即 monitor 对象监视器。
monitorenter,monitorexit
Java 对象
包含对象头、实例数据、对齐填充。
对象头包含:对象自身的运行数据,如:哈希码、GC 分代年龄、锁标志位、持有该对象锁的线程数(每次monitorenter时加一)、指向轻量级锁记录的指针、指向重量级锁的指针、GC 标记等。
重量级锁:非可重入的锁
CAS:通过 Linux 内核中的 cmpxchg 函数来实现。
synchronized:加锁(偏向锁-》轻量级锁-〉重量级锁)。把 monitor 加入到 JVM 维护的阻塞队列。ContentionList -》EntryList -〉。。。
wait():释放锁,并加入到阻塞队列
自旋锁:循环进行 cmpxchg。为减少线程上下文切换而引入的。
Lock:使用自旋锁,cas
偏向锁:第一次拿到锁后,第二次如果还是第一次拿个线程,就不加锁直接进入,反之 cas。偏向锁遇到抢占锁而发生竞争时,会升级为轻量级锁。
轻量级锁:用 cas 。自旋失败会升级为重量级锁。
重量级锁:加锁
Thread
Java 每个线程内有父线程的引用,在 Linux 中所有的线程都是由父线程 fork 出来的。
一个线程必须拥有一个组。
sleep:不释放 monitor,即不释放锁。
yield:把当前占有的内核线程,让步给其他等待调用的线程。如果没有其他等待的线程,那么这方法不让步。
stop:停止线程。直接释放所占有的所有锁。
start:启动后进入就绪状态。
interrupt:中断。
suspend:挂起。不会释放锁。
resume:恢复一个挂起的线程。
join:在当前线程中加入另一个线程,在新加入的线程没有执行完毕之前,当前线程无法继续执行。
Object
wait、notify、notifyAll 只能在同步方法、同步代码块内部调用。
wait:阻塞,释放锁,进入等待池。notify、notifyAll 后才会继续等待调度。