美文网首页
Java多线程(三)Java 显式锁

Java多线程(三)Java 显式锁

作者: GIT提交不上 | 来源:发表于2019-09-25 23:04 被阅读0次

    一、Lock接口

      Lock接口声明了手动获取锁和释放锁的方法,Lock接口具有锁的可操作性,可中断获取以及超时获取锁等多种同步特性。Lock接口源码如下所示:

    public interface Lock {
        void lock();
        void lockInterruptibly() throws InterruptedException;
        boolean tryLock();
        boolean tryLock(long var1, TimeUnit var3) throws InterruptedException;
        void unlock();
        Condition newCondition();
    }
    

      lock方法会忽略中断请求,继续获取锁直到成功;而lockInterruptibly则直接抛出中断异常来立即响应中断,由上层调用者处理中断。以ReentrantLock为例,ReentrantLock部分源码如下所示:

        public void lockInterruptibly() throws InterruptedException {
            sync.acquireInterruptibly(1);
        }
    
        public final void acquireInterruptibly(int arg)
                throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            if (!tryAcquire(arg))
                doAcquireInterruptibly(arg);
        }
    

      结合ReentrantLock可重入锁测试 lock.lockInterruptibly()方法,当线程被中断时,直接抛出InterruptedException异常。

    public class Test implements Runnable {
        private Lock lock = new ReentrantLock();
        private int count = 0;
        public void update() {
            this.count++;
            System.out.println(String.valueOf(count) + Thread.currentThread());
        }
        @Override
        public void run() {
    //        try {
    //            lock.lock();
    //            System.out.println("I am sleeping!" + Thread.currentThread());
    //            this.update();
    //
    //            System.out.println("hello world");
    //        } finally {
    //            lock.unlock();
    //        }
    
            try {
                lock.lockInterruptibly();
                System.out.println("Thread info:" + Thread.currentThread());
                this.update();
            } catch (InterruptedException e) {
                System.out.println("Get InterruptedException!");
            } finally {
                lock.unlock();
            }
        }
    
        public static void main(String[] args) {
            Test test = new Test();
            Thread t1 = new Thread(test);
            t1.start();
            t1.interrupt();  // 抛出nterruptedException异常
        }
    }
    

    二、ReentrantLock(可重入锁)

      支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁(即允许一个线程多次获取同一个锁),分为公平锁和非公平锁(默认)。ReentrantLock通过组合自定义同步器实现锁的获取与释放,部分源码如下所示:

            //非公平锁获取锁
            final boolean nonfairTryAcquire(int acquires) {
                final Thread current = Thread.currentThread();
                int c = getState();
                if (c == 0) {
                    if (compareAndSetState(0, acquires)) {
                        setExclusiveOwnerThread(current);
                        return true;
                    }
                }
                else if (current == getExclusiveOwnerThread()) {
                    int nextc = c + acquires;
                    if (nextc < 0) // overflow
                        throw new Error("Maximum lock count exceeded");
                    setState(nextc);
                    return true;
                }
                return false;
            }
    
            //释放锁
            protected final boolean tryRelease(int releases) {
                int c = getState() - releases;
                if (Thread.currentThread() != getExclusiveOwnerThread())
                    throw new IllegalMonitorStateException();
                boolean free = false;
                if (c == 0) {
                    free = true;
                    setExclusiveOwnerThread(null);
                }
                setState(c);
                return free;
            }
    

      公平锁保证了锁的获取按照FIFO原则,代价是进行大量的线程切换。非公平锁可能会造成线程饥饿,但线程切换少,保证了更大的吞吐量。
      ReentrantLock具体实例如下所示:

    public class LockTest implements Runnable{
        private Lock lock = new ReentrantLock();
         public void update(){
            this.count++;   
            System.out.println(count);
        }
        @Override
        public void run() {
            lock.lock();
            try{
                this.update();
            } finally {
                lock.unlock();
            }
        }
        public static void main(String[] args){
            LockTest test = new LockTest();
            for(int i = 0; i< 10; i++){
                new Thread(test).start();
            }
        }
    }
    

    三、 ReadWriteLock接口

      读写锁在同一时刻可以允许多个线程读线程访问,但是在写线程访问时,所有的读线程和其他写线程均被阻塞。读写锁接口定义了只读锁和写锁,其源码如下所示:

    public interface ReadWriteLock {
        Lock readLock();
        Lock writeLock();
    }
    

      锁降级:从写锁变成读锁;锁升级(不支持):从读锁变成写锁。

    四、ReentrantReadWriteLock(读写锁)

      读写锁支持非公平(默认)和公平的锁获取方式;支持锁的重进入;支持锁降级。具体实例如下所示:

    public class Test implements Runnable{
        private ReadWriteLock lock = new ReentrantReadWriteLock();
        private Lock readLock = lock.readLock();
        private Lock writeLock = lock.writeLock();
        private Boolean flag;
        private int count = 0;
        public Test(boolean flag){
            this.flag = flag;
        }
        public void readFile(){
            readLock.lock();
            try {
                System.out.println(Thread.currentThread() + ":正在进行读操作!");
                int res = this.count;
                System.out.println(Thread.currentThread() + ":读操作完毕,读取的值为:"+res+"!");
            }
            finally {
                readLock.unlock();
            }
        }
    
        public void writeFile(){
            writeLock.lock();
            try {
                System.out.println(Thread.currentThread() + ":正在进行写操作!");
                this.count++;
                System.out.println(Thread.currentThread() + ":写操作完毕,最新值为:"+this.count+"!");
            }finally {
                writeLock.unlock();
            }
        }
    
        @Override
        public void run() {
            if (flag){
                this.writeFile();
            }
            else {
                this.readFile();
            }
        }
    
        public static void main(String[] args) {
            boolean flag = new Random().nextInt(10) > 5 ?true:false;
            Test test = new Test(flag);
            for (int i=0;i< 10;i++){
                new Thread(test).start();
            }
        }
    }
    

      锁降级实例如下所示:

       public void writeFile(){
            writeLock.lock();
            try {
                System.out.println(Thread.currentThread() + ":正在进行写操作!");
                this.count++;
                System.out.println(Thread.currentThread() + ":写操作完毕,最新值为:"+this.count+"!");
    
                readLock.lock();
                System.out.println(Thread.currentThread() + ":获取到读锁!");
                int res = this.count;
                System.out.println(Thread.currentThread() + ":读操作完毕,读取的值为:"+res+"!");
            }finally {
                writeLock.unlock();
            }
            try {
    
            }finally {
                readLock.unlock();
            }
        }
    

    相关文章

      网友评论

          本文标题:Java多线程(三)Java 显式锁

          本文链接:https://www.haomeiwen.com/subject/thciuctx.html