java语言中的锁

  1. 从java的集合线程安全开始说起
    1. 平时经常使用的集合类如ArrayList,LinkedList,HashSet等以及Map都是线程不安全的,如果进行多线程操作会出现线程安全问题,那么java是如何解决这些常用类的线程安全问题呢
    2. 几个常用的保证集合类线程安全的方法
      1. 使用synchronized关键字
      2. 使用Collections提供的工具方法保证线程安全,底层还是使用Synchronized关键字

        Collections.synchronizedCollection(list)
        Collections.synchronizedList()
        Collections.synchronizedSet();
        Collections.synchronizedMap();

      3. 使用juc包中的提供的集合类:

        CopyOnWriteArrayList
        CopyOnWriteArraySet
        ConcurrentHashMap

        copyOnWrit类在新增元素的时候,会将add方法加锁,防止其他线程调用add方法时产生线程不安全问题。在加锁后,回将底层保存元素的数组copy一份,并利用这个拷贝的副本创建一个新的数组,然后将要追加的元素放到新数组中, 最后保存元素的数组指向包含要追加元素的新数组,然后解锁

  2. 使用锁和synchronized来保证线程安全的对比

    1. 原始构成
      1. synchronized是java的关键字,是在jvm层面的实现,底层利用moniter实现
        1. jvm层面在进入被synchronized块包围的代码块是执行 moniterenter命令,跳出时执行moniterexit命令
      2. lock是在语言层面的实现,它是在jdk5之后新出现的一个java类
    2. 使用方法
      1. 使用synchronized关键字不需要用户手动释放锁,即使代码出现异常锁也会被释放
      2. 使用lock需要手动释放锁,否则会出现死锁情况;配合try–catch-finally代码块使用lock,unlock加锁,释放锁
    3. 等待是否可中断
      1. synchronized的不能被中断,一旦进入synchronized代码块,代码要不正常执行完,要么出现异常跳出代码块
      2. 使用lock可以出现中断
    4. 是否是公平锁
      1. synchronized为非公平锁
      2. lock可以是公平锁也可以是非公平锁,默认是非公平锁
    5. 锁绑定多个条件condition
      1. lock可以实现分组唤醒,可以精确唤醒需要唤醒的线程,而synchronized要么唤醒一个线程要么唤醒全部线程,无法精确控制
        lock绑定多条件示例代码见 iqijun/javastudy
  3. java中锁的分类
    1. 公平锁和非公平锁
      1. 公平锁是指按申请锁的顺序来获得锁
      2. 非公平锁是指随机抢占锁,而不是按照顺序获得
      3. 非公平锁可能会造成优先级反转问题和饥饿现象(线程长时间获取不到锁),但非公平锁的吞吐量比较大
      4. ReentrantLock默认为非公平锁,synchronized也是非公平锁
    2. 可重入锁(递归锁)
      1. 可重入锁是指当线程获得了外层方法的锁之后,也可以进入到需要相同锁的内部方法。而不需要在进入到内部方法时重新获取锁。
      2. 比如
        /**
         * @program: course
         * @description: 重入锁演示
         * 重入锁又叫递归锁,当线程在外城方法中获得到锁以后,它边默认可以进入到需要相同锁的内部方法中
         * 如示例中methodA和methodB都需要获得lock,当线程在进入到methodA中时获取到lock,那边它便可以顺利进入到methodB中
         * 而不需要在进入到methodB的时候重新获取锁
         * @author: xingguishuai
         * @create: 2019-05-25 14:45
         */
        public class ReentredLockDemo {
        
            Lock lock  = new ReentrantLock();
        
            public static  void main(String[] args){
               final   ReentredLockDemo reentredLockDemo = new ReentredLockDemo();
                for (int i = 0; i < 10; i++) {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            reentredLockDemo.methodA();
                        }
                    },"Thread_"+i).start();
                }
            }
        
        
            public void methodA(){
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName()+"进入mthodA,获得到锁");
                    methodB();
                }catch (Exception e){
        
                }finally {
                    lock.unlock();
                }
        
            }
        
            public  void methodB(){
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName()+"进入mthodB,获得到锁");
                }catch (Exception e){
        
                }finally {
                    lock.unlock();
                }
            }
        
        }
        
      3. 可重入锁的好处是可以有效避免死锁现象。这是因为减少了锁抢占

      4. ReentrantLock,synchronized都是可重入锁

    3. 独享锁、共享锁

      1. 独享锁是指该锁一次只能被一个线程所持有。共享锁是指该锁可被多个线程所持有。

        ReentrantLock,synchronized都是独享锁,ReadWriteLock的readLock是共享锁

        1. 共享锁和不加锁的区别

        加的共享锁之后,就不能再次加独享锁。可以实现多条线程去读,但读的同时不能有写操作

    4. 自旋锁

      自旋锁是指在线程获取锁不成功的时候,不会将线程阻塞,而是通过不断的重试来获取锁.

      自旋锁的好处是减少了线程上下文切换的消耗

      但由于自旋锁通过循环不停的尝试获取锁,会造成cpu的消耗

  4. java中锁的实现原理

java中锁是完全利用java语言实现的,它的实现利用了cas原理和AbstractQueuedSynchronizerl类

创作不易,转载请注明文章来源为www.full-satcker.com:邢桂帅 » java语言中的锁

赞 (2)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址