Java高级开发

JAVA锁相关

2020-01-12  本文已影响0人  依弗布德甘

Java锁的概念


自己实现锁-不可重入锁

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;

public class DemoLock implements Lock {

    //锁的拥有者
    AtomicReference<Thread> owner = new AtomicReference<>();

    //等待队列
    private LinkedBlockingQueue<Thread> waiter = new LinkedBlockingQueue<>();


    @Override
    public boolean tryLock() {
        return owner.compareAndSet(null, Thread.currentThread());
    }

    @Override
    public void lock() {
        if (!tryLock()){
            // 抢锁不成功,加入等待队列
            waiter.offer(Thread.currentThread());
            // 用死循环防止为唤醒问题
            while(true){
                // 去除队列头部,但是不出队列
                Thread head = waiter.peek();
                // 判断是队列头部
                if (head == Thread.currentThread()){
                    // 抢锁
                    if(!tryLock()){
                        //失败,挂起线程
                        LockSupport.park();
                    }else{
                        //抢锁成功,将线程出度列
                        waiter.poll();
                        return;
                    }
                }else{
                    //不是头部,线程挂起
                    LockSupport.park();
                }
            }
        }
    }

    @Override
    public void unlock() {
        if (tryUnlock()){
            Thread th = waiter.peek();
            if (th !=null){
                LockSupport.unpark(th);
            }
        }
    }

    public boolean tryUnlock(){
        //首先判断当前线程是否站有锁
        if (owner.get() !=Thread.currentThread()){
            throw new IllegalMonitorStateException();
        }else{
            return owner.compareAndSet(Thread.currentThread(), null);
        }
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public Condition newCondition() {
        return null;
    }
}

可重入锁和不可重入锁的区别
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantTest {

    private static  int i = 0;

    private final static Lock lc1 = new ReentrantLock();     //可重入锁
    private final static Lock lc2 = new DemoLock();   //不可重入锁

    public static void recursive() throws InterruptedException {
        lc1.lock();
        i++;
        System.out.println("here i am...");
        Thread.sleep(1000L);
        // 休眠一秒后重新执行该方法,lock不影响
        recursive(); 

        lc1.unlock();
    }

    public static void main(String args[]) throws InterruptedException {
        lc2.lock();
        System.out.println("加锁第一次。。。");
        lc2.lock();
        // 第二次加锁后,线程阻塞,不执行
        System.out.println("加锁第二次。。。");

        lc.unlock();
        lc.unlock();

        //recursive();
    }

}

同步关键字synchronized

synchronized关键字通过修饰一个方法或声明一个代码块,从而产生一个同步对象锁以及对应的同步代码块,是通过锁对象的Monitor的取用与释放来修改其对象的头部信息,实现加锁解锁

// ObjectMonitor底层结构 C++代码
ObjectMonitor::ObjectMonitor() {
  _header       = NULL;
  _count        = 0;
  _waiters      = 0,
  _recursions   = 0;
  _object       = NULL;
  _owner        = NULL;
  _WaitSet      = NULL;
  _WaitSetLock  = 0 ;
  _Responsible  = NULL ;
  _succ         = NULL ;
  _cxq          = NULL ;
  FreeNext      = NULL ;
  _EntryList    = NULL ;
  _SpinFreq     = 0 ;
  _SpinClock    = 0 ;
  OwnerIsThread = 0 ;
}
import com.study.lock.source.bak.ReentrantLock;
import java.util.concurrent.locks.Lock;

public class Demo {
    public static void main(String args[]){
        //如果你在实例方法上加锁,
        //多个线程,抢的是同一个所,还是多个锁
        //Counter ct1 = new Counter();
        //Counter ct2 = new Counter();

        new Thread(new Runnable() {
            @Override
            public void run() {
                Counter.staticUpdate();
                //ct1.update();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                Counter.staticUpdate();
                //ct1.update();
            }
        }).start();
    }
}


class Counter{

    private static int i = 0;
 
    public synchronized void update() {
        //访问数据库
    }
    
    // 与update的写法语意一致
    public void updateBlock(){
        synchronized (this){
            //访问数据库
        }
    }
 
    public static synchronized void staticUpdate(){
        //访问数据库
    }

    // 与staticUpdate的写法语意一致
    public static void staticUpdateBlock(){
        synchronized (Counter.class){
            //访问数据库
        }
    }

    Lock lock = new ReentrantLock();
    public void updateReentrantLock(){
        lock.lock();
        try {
           //访问数据库
        }finally {
            lock.unlock();
        }
    }
}

    public void test(Object arg) {
        // StringBuilder线程不安全,StringBuffer用了synchronized,是线程安全的
        // 局部变量,没有在其他线程中使用
        // 每次append都用了synchronized
        // jit 优化, 消除了锁
        StringBuffer stringBuffer = new StringBuffer();   
        stringBuffer.append("a"); 
        stringBuffer.append("b");
        stringBuffer.append("c");
 
        stringBuffer.append("a");
        stringBuffer.append("b");
        stringBuffer.append("c");

        System.out.println(stringBuffer.toString());
    }
    volatile int i = 0;

    public void test(Object arg) { 
        // 每次加锁都对 i 操作
        // jit 优化, 合并锁
        synchronized (this){
            i++;
            i--;
            //生成随机数  
        }
        synchronized (this){ 
            //生成随机数  
            i--;
        } 
    }

synchronized 底层原理

public class Demo {
    public static void main(String args[]){
        int a = 1;
        Teacher teacher = new Teacher();
        teacher.stu = new Student();
    }
}

class Teacher{
    String name = "james";
    int age = 40;
    boolean gender = true;
    Student stu;

    public void shout(){
    }
}

class Student{
    String name = "Emily";
    int age = 18;
    boolean gender = false;
}
内存中的存储方式 轻量级锁,抢锁流程
  1. 两个线程抢锁之前,会先读取MarkWord的值
  2. 两个线程抢锁之前,会先读取MarkWord的值
  3. CAS操作会抢锁,只会有一个线程抢到锁
  4. 线程1抢到锁后,对象头部成为轻量级锁
  5. 线程2未抢到锁,将自旋
  6. 自旋一定程度,锁升级。CAS操作将把锁改为重量级锁
重量级锁
  1. 线程1对当前对象抢锁成功后,对象onwer等于线程1。线程2自旋
  2. 自旋到一定程度,锁升级,线程2加入锁池,并持续抢锁
  3. 线程1调用wait()方法后,线程1释放锁,并加入WaitSet等待池中。onwer等于空
  4. 线程2抢锁成功,onwer等于线程2,线程2出entryList(锁池),执行线程2
  5. 线程2执行完毕,线程1.notify()方法,线程1退出等待池,onwer等于线程1
  6. 如果此时线程2又来抢锁,线程2加入锁池

wait、notify和notifyAll方法是Object类的final native方法,这些方法不能被子类重写;
wait只能在同步方法中调用notify和notifyAll只能在同步方法或同步块内部调用;

上一篇 下一篇

猜你喜欢

热点阅读