线程主动让出CPU
如何让线程主动让出CPU
由于等待一个锁的线程只有在获得这把锁之后,才能恢复运行,所以让持有锁的线程在不再需要锁的时候及时释放锁是很重要的。在以下情况下,持有锁的线程会释放锁:
(1)执行完同步代码块,就会释放锁。(synchronized执行完毕解锁)
(2)在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会被释放。(exception异常)
(3)在执行同步代码块的过程中,执行了锁所属对象的wait()方法,这个线程会释放锁,进入对象的等待池。(wait方法被调用)
除了以上情况以外,只要持有锁的线程还没有执行完同步代码块,就不会释放锁。
在下面情况下,线程是不会释放锁的:
(1)执行同步代码块的过程中,执行了Thread.sleep()方法,当前线程放弃CPU,开始睡眠,在睡眠中不会释放锁。
(2)在执行同步代码块的过程中,执行了Thread.yield()方法,当前线程放弃CPU,但不会释放锁。
(3)在执行同步代码块的过程中,其他线程执行了当前线程对象的suspend()方法,当前线程被暂停,但不会释放锁。
Thread.sleep();
sleep就是正在执行的线程主动让出cpu,cpu去执行其他线程,在sleep指定的时间过后,cpu才会回到这个线程上继续往下执行,如果当前线程进入了同步锁,sleep方法并不会释放锁,即使当前线程使用sleep方法让出了cpu,但其他被同步锁挡住了的线程也无法得到执行。
在多线程争用的情况,拥有锁的线程进行一些耗时操作,会极大降低吞吐量(amdahl定律),如果在同步块中使用sleep就是一种糟糕的做法,它不会释放锁却阻止其他线程获得锁。
Thread.yield();
yeild是个native静态方法,这个方法是想把自己占有的cpu时间释放掉,然后和其他线程一起竞争(注意yeild的线程还是有可能争夺到cpu,注意与sleep区别)。在javadoc中也说明了,yeild是个基本不会用到的方法,一般在debug和test中使用。
Object.wait();
wait会把当前的锁释放掉同时阻塞住,让出CPU;当别的线程调用该 Object 的 notify/notifyAll 之后,有可能得到 CPU,同时重新获得锁。
当然同样的
condition.await();
也会释放锁并且让出CPU;
当然很多竞争锁失败的线程最终也会阻塞住,但是这不是主动让出CPU,不在讨论范围内。
Thread.stop();
太过暴力,不推荐使用,同时会释放所有锁。容易导致数据不一致,具体请查看[高并发Java 二] 多线程基础
Thread.currentThread().suspend();
挂起线程,suspend不会释放锁,suspend容易发生死锁,不推荐使用。原因请查看[高并发Java 二] 多线程基础
LockSupport.park();
与suspend一样挂起线程,但是park/unpark不会发生死锁,原因请查看[高并发Java 五] JDK并发包1
Java中Thread的状态有:
NEW
RUNNABLE
WAITING:Object.wait(),LockSupport.park()
TIMED_WAITING:Thread.sleep(long),Object.wait(long),LockSupport.parkNanos(long)
BLOCKED:Object.wait()
TERMINATED:Thread.stop()
如何让线程主动放弃持有的锁
Object.wait();
condition.await();
Thread.stop();
上面已经说了
当然所有释放锁的操作都可以:
reentrantLock.unlock();
semaphore.release();
要注意的是以下操作不会释放锁,在上面已经谈到了,这里再列举以下:
Thread.sleep();
Thread.yield();
Thread.currentThread().suspend();
LockSupport.park();