1.多线程情况下自己手动模拟实现一把锁(伪代码)
- Version1.0:自旋
-
volatile int status = 0; //是否有线程获取到锁,0表示没有 //主业务流程 public static void testSync() { thread.lock(); //当前线程尝试获取锁 ... //获取到锁之后处理业务逻辑 thread.unlock(); //最后需要释放锁 } //加锁流程 public void lock() { while(!CAS(0,1)) //CAS(0,1); 比较当前status值是否为0,如果是的话返回true,否则返回false { //自旋 } } public void unlock() { status = 0; } public boolean CAS(int oldVlaue, int newValue) { //CAS操作,修改status的值成功返回true,否则返回false }
- Version1.0版本虽然能够实现加锁互斥操作,但是lock方法里面的while循环会自旋,一直消耗CPU,有待改进!
Version2.0:yield+自旋
volatile int status = 0; //是否有线程获取到锁,0表示没有
//主业务流程
public static void testSync()
{
thread.lock(); //当前线程尝试获取锁
... //获取到锁之后处理业务逻辑
thread.unlock(); //最后需要释放锁
}
//加锁流程
public void lock()
{
while(!CAS(0,1)) //CAS(0,1); 比较当前status值是否为0,如果是的话返回true,否则返回false
{
yield();
}
}
public void unlock()
{
status = 0;
}
public boolean CAS(int oldVlaue, int newValue)
{
//CAS操作,修改status的值成功返回true,否则返回false
}
- while里面使用yield();目的是让出CPU,解决忙循环问题,让自己或者其他线程去抢占CPU。但这样还是有问题,如果线程数在两个以上并不能控制具体哪个线程获取CPU。
Version3.0:sleep + 自旋:这种情况并不能保证sleep睡多长时间合适。
Version4.0:park+自旋
-
volatile int status = 0; //是否有线程获取到锁,0表示没有 Queue parkQueue; //队列,用来存放阻塞的线程 //加锁流程 public void lock() { while(!CAS(0,1)) //CAS(0,1); 比较当前status值是否为0,如果是的话返回true,否则返回false { park(); //当前线程阻塞 } ... //处理业务逻辑 unlock(); } public void unlock() { status = 0; Thread t = parkQueue.header(); //得到队列头部线程 unpark(t); //唤醒t线程 } public void park() { parkQueue.add(currentThread); //当前线程加入阻塞队列 releaseCpu(); //释放CPU资源 } public boolean CAS(int oldVlaue, int newValue) { //CAS操作,修改status的值成功返回true,否则返回false }
使用park的好处是:能够指定让某个线程阻塞或者唤醒。