• 同步锁之lock


    一、 synchronized的缺陷

    当一个代码块被synchronized修饰时,同时该代码块被一个线程执行,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:

     1)获取锁的线程执行完成代码块,自动释放锁资源

     2)代码块中执行异常,由jvm释放锁资源

     如果在执行代码块时候,一个线程在代码块执行过程中Thread.sleep() 睡眠  线程被阻塞了,其他线程只能等待当前线程执行完成后才能执行。及其浪费效率。

    另外当多个线程在执行写与写操作时,会发生线程冲突,但当多个线程用于读操作,其中一个线程读取占用的锁资源  而其他线程只能等待造成浪费资源。

    通过多个线程读取操作线程不会冲突,通过lock可以实现。

    不同点:

       synchronized是java内置的,是java关键字,lock 是一个接口  不是内置的通过这个接口可以实现同步访问

       synchronized不需要用户手动释放锁资源,当同步方法或者同步代码块执行完成后,系统会自动让线程释放锁资源。而Lock必须要手动释放锁资源,如果不释放会出现死锁

    二、 java.util.concurrent.locks包下常用的类

     1) Lock 是一个接口

         提供了六个方法

         void lock();    boolean tryLock(); boolean tryLock(long time,timeUnit unit); void  lockInteruptibly(); contition newContition()  void unlock();

        其中lock()  tryLock()   tryLock(long time,timeUnit unit)  lockInteruptibly() 用于获取锁    unlock() 用于释放锁

         由于采用lock  不会自动释放锁,需要手动释放锁  所以采用lock 必须在try{}catch(){}finally{}异常捕获中进行,在finally中释放锁

        lock()是最常用的获取锁的方式

         例子:

           Lock lock = ..

           lock.lock();

          try{

       }catch(Exception e){

             }finally{

        lock.unlock()

      }

       

        tryLock 尝试获取锁,如果获取到返回true 如果获取不到返回false   不会拿不到锁一致在等待

        tryLock(long time,TimeUnit unit) 与tryLock()一样都是尝试获取锁,如果获取到返回true  否则返回false  区别在于tryLock(long time ,TimeUnit unit)会等待一定时间,如果直接获取到锁返回true 或者在设置的等待时间内获取到锁返回true  否则返回flase

        Lock lock = ..

        if(lock.tryLock()){

      try{

      }catch(){

          }finally{

       lock.unlock(); 

         }

     }

        lockInterruptibly() 可以用来获取锁,但是如果在获取的锁已经被其他线程锁占用  在等待过程中可以中断当前线程的等待状态。通俗的将  如果 a  b两个线程通过Lock.lockInterruptibly()获取某一个锁时,如果a先获取到了锁   b处于等待状态 那么b可以调用b.interrup()方法中断b的等待状态

      由于lockInterruptibly()的声明中抛出了异常,所以lock.lockInterruptibly()必须放在try块中或者在调用lockInterruptibly()的方法外声明抛出InterruptedException。

       public void method () throws InterruptedException{

      lock.Interruptibly();

           try{

      }catch(){

          }finally{

           lock.unlock();

         }

     }

      当一个线程获取到了锁 是不会被interrup()方法中断  只有处于等待状态的线程在才能被中断。

    2)ReentrantLock  可重入锁

        ReentrantLock是Lock接口的唯一实现类

        Lock 接口的实现方式:

      

    package cn.ac.bcc.lock;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class LockDemo {
        
        private List<Integer> list = new ArrayList<>();
    
        
        public static void main(String[] args) {
            
            //实例化当前类对象
            final LockDemo ld = new LockDemo();
            //创建两个线程对象  调用insert方法
             new Thread(new Runnable(){
                @Override
                public void run() {
                    
                  ld.insert(Thread.currentThread());
    
                }
                
            }).start();
             
             new Thread(new Runnable(){
    
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    ld.insert(Thread.currentThread());
                }
                 
             }).start();
        }
        
        public void insert(Thread thread){
            
            //创建局部lock锁对象
            Lock lock = new ReentrantLock();
            System.out.println(lock);
            //获取锁
            lock.lock();
            try {
                for(int i=0;i<5;i++){
                    list.add(i);
                }
                System.out.println(Thread.currentThread().getName()+"获取了锁");
            } catch (Exception e) {
                // TODO: handle exception
            }finally{
                //释放锁
                lock.unlock();
                System.out.println(Thread.currentThread().getName()+"释放了锁");
            }
        }
    
    }
    View Code

    运行结果:

      

    java.util.concurrent.locks.ReentrantLock@100363[Unlocked]
    java.util.concurrent.locks.ReentrantLock@e0a386[Unlocked]
    Thread-0获取了锁
    Thread-1获取了锁
    Thread-0释放了锁
    Thread-1释放了锁

    产生这种结果的原因: 当多个线程获取同一个对象的方法中的局部变量,每一个线程都会获取一个局部变量lock的副本   通过打印锁对象地址可以发现当前锁对象是不同的锁 所以他们可以获取不同的锁

    解决这种方案:

     将获取锁对象成员变量  属于当前对象

    package cn.ac.bcc.lock;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class LockDemo {
        
        private List<Integer> list = new ArrayList<>();
        //创建局部lock锁对象
        private Lock lock = new ReentrantLock();
        
        public static void main(String[] args) {
            
            //实例化当前类对象
            final LockDemo ld = new LockDemo();
            //创建两个线程对象  调用insert方法
             new Thread(new Runnable(){
                @Override
                public void run() {
                    
                  ld.insert(Thread.currentThread());
    
                }
                
            }).start();
             
             new Thread(new Runnable(){
    
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    ld.insert(Thread.currentThread());
                }
                 
             }).start();
        }
        
        public void insert(Thread thread){
            
    
            System.out.println(lock);
            //获取锁
            lock.lock();
            try {
                for(int i=0;i<5;i++){
                    list.add(i);
                }
                System.out.println(Thread.currentThread().getName()+"获取了锁");
            } catch (Exception e) {
                // TODO: handle exception
            }finally{
                //释放锁
                lock.unlock();
                System.out.println(Thread.currentThread().getName()+"释放了锁");
            }
        }
    
    }
    View Code

    运行结果:

    java.util.concurrent.locks.ReentrantLock@bcda2d[Unlocked]
    java.util.concurrent.locks.ReentrantLock@bcda2d[Locked by thread Thread-0]
    Thread-0获取了锁
    Thread-0释放了锁
    Thread-1获取了锁
    Thread-1释放了锁

    tryLock()

    package cn.ac.bcc.lock;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class LockDemo {
        
        private List<Integer> list = new ArrayList<>();
        //创建局部lock锁对象
        private Lock lock = new ReentrantLock();
        
        public static void main(String[] args) {
            
             //实例化当前类对象
             final LockDemo ld = new LockDemo();
            //创建两个线程对象  调用insert方法
             new Thread(new Runnable(){
                @Override
                public void run() {
                    
                  ld.insert(Thread.currentThread());
    
                }
                
            }).start();
             
             new Thread(new Runnable(){
    
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    ld.insert(Thread.currentThread());
                }
                 
             }).start();
        }
        
        public void insert(Thread thread){
            
    
            System.out.println(lock);
            //获取锁
            if(lock.tryLock()){
                try {
                    for(int i=0;i<5;i++){
                        list.add(i);
                    }
                    System.out.println(Thread.currentThread().getName()+"获取了锁");
                } catch (Exception e) {
                    // TODO: handle exception
                }finally{
                    //释放锁
                    lock.unlock();
                    System.out.println(Thread.currentThread().getName()+"释放了锁");
                }
            }else{
                System.out.println(Thread.currentThread().getName()+"没有获取到锁");
            }
            
        }
    
    }
    View Code

    运行结果:

    java.util.concurrent.locks.ReentrantLock@14e8cee[Unlocked]
    java.util.concurrent.locks.ReentrantLock@14e8cee[Locked by thread Thread-0]
    Thread-1没有获取到锁
    Thread-0获取了锁
    Thread-0释放了锁

    当多个线程获取同一个锁对象时,当线程a 获取锁  b尝试获取锁失败返回false

    lockInterruptibly()

    package cn.ac.bcc.lock;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class InterruptiblyDemo {
    
        Lock lock = new ReentrantLock();
        
        public static void main(String[] args) {
            
            InterruptiblyDemo interruptiblyDemo = new InterruptiblyDemo();
            
            MyThread myThread = new MyThread(interruptiblyDemo);
            MyThread myThread2 = new MyThread(interruptiblyDemo);
            myThread.start();
            myThread2.start();
            
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            //中断线程2
            myThread2.interrupt();
        }
        
        public  void  insert() throws InterruptedException{
            lock.lockInterruptibly();
            try{
                System.out.println(Thread.currentThread().getName()+"得到了锁");
                long startTime = System.currentTimeMillis();
                for(;;){
                    
                    if(System.currentTimeMillis()-startTime>=Integer.MAX_VALUE){
                        break;
                    }
                    
                }
            }catch(Exception e){
                e.printStackTrace();
            }finally{
                System.out.println(Thread.currentThread().getName()+"释放了锁");
                lock.unlock();
            }
        }
    }
    class MyThread extends Thread{
        
        InterruptiblyDemo interruptiblyDemo;
        
        public MyThread(InterruptiblyDemo interruptiblyDemo){
            this.interruptiblyDemo=interruptiblyDemo;
        }
        
        @Override
        public void run(){
            try {
                interruptiblyDemo.insert();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                System.out.println(Thread.currentThread().getName()+"锁被中断");
            }
        }
        
    }
    View Code

    运行结果:

    Thread-0得到了锁
    java.lang.InterruptedException
    Thread-1锁被中断
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:896)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1221)
    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:340)
    at cn.ac.bcc.lock.InterruptiblyDemo.insert(InterruptiblyDemo.java:30)
    at cn.ac.bcc.lock.MyThread.run(InterruptiblyDemo.java:60)

      

         

      

        https://www.cnblogs.com/baizhanshi/p/6419268.html

  • 相关阅读:
    代码格式化[转]
    ASP.NET错误大杂烩
    Web考勤管理系统 .net 2005 开发
    Ftp 类
    c#中Split等分割字符串的几种方法
    强大的firebug 使用 介绍
    一页面多个文本框回车提交不同事件问题解决
    Ajax电子书下载 发现的好东东贴上了
    编程技术书籍[转]
    推荐下权威的《IT十年经典书系列》1打
  • 原文地址:https://www.cnblogs.com/lwdmaib/p/9266326.html
Copyright © 2020-2023  润新知