多线程同步内部如何实现
wait/notify, synchronized, ReentrantLock, 等
synchronized: 重量级 调用操作系统的函数
jdk1.6以前
private native void start0(); ---调用openjdk中的c文件---c文件调用操作系统函数---启动线程
JVM中的线程=操作系统中的线程 线程同步会使CPU由用户态切换为内核态
jdk1.7以后
尽量由JVM解决
Thread.yield()方法作用是:暂停当前正在执行的线程对象,并执行其他线程。
yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。
结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。
LockSupport.park(); LockSupport封装了unsafe中的park()
park立即阻塞线程
unpark获取许可继续运行
实现一把锁的基本思路
park+自旋
volatile int status=0;
Queue parkQueue;//队列
void lock(){
while(!compareAndSet(0,1)){//判断status能不能加锁,如果=0则变为1加锁成功,等于1则加锁失败
//
park();
}
//lock 20s
.....
unlock();
}
void unlock(){
status=0;
lock_notify();
}
void park(){
将当前线程加入到等待队列
parkQueue.add(currentThread);
//将当前线程释放cpu 阻塞
releaseCpu();
}
void lock_notify(){
//得到要唤醒的队列首线程
Thread t = parkQueue.header();
//唤醒等待线程
LockSupport.unpark(t);
}
将unlock放在finally{}中,确保即使抛出异常也会释放锁。
ReentrantLock中的abstract void lock()有两个实现类
FairSync 公平锁
NonfairSync 非公平锁
默认构造方法是非公平锁 static ReentrantLock l = new ReentrantLock();
加true参数是公平锁 static ReentrantLock l = new ReentrantLock(true);
ReentrantLock出现的原因是1.6之前synchronized关键字不管是线程并发竞争执行还是交替执行都是重量级锁,都会调用操作系统的函数,C++,ReentrantLock在交替执行时是轻量级锁
1.7以后ReentrantLock与synchronized没有区别
但是ReentrantLock提供了丰富的api