• JAVA并发包——锁


    1.java多线程中,可以使用synchronized关键字来实现线程间的同步互斥工作,其实还有个更优秀的机制来完成这个同步互斥的工作——Lock对象,主要有2种锁:重入锁和读写锁,它们比synchronized具有更强大的功能,并且有嗅探锁定、多路分支等功能。

    2.ReentrantLock(重入锁)

    重入锁,在需要进行同步的代码部分加上锁定,但不要忘记最后一定要释放锁定,否则会造成锁永远无法释放,其他线程永远进不来的结果(使用起来跟synchronized很像,并且,在jdk1.8之前,ReentrantLock比synchronized性能好,jdk1.8对synchronized做了优化,性能接近了。但是ReentrantLock比synchronized灵活)

    代码示例:

     1 package lock020;
     2 
     3 import java.util.concurrent.locks.Lock;
     4 import java.util.concurrent.locks.ReentrantLock;
     5 
     6 public class UseReentrantLock {
     7     
     8     private Lock lock = new ReentrantLock();
     9     
    10     public void method1(){
    11         try {
    12             lock.lock();
    13             System.out.println("当前线程:" + Thread.currentThread().getName() + "进入method1..");
    14             Thread.sleep(1000);
    15             System.out.println("当前线程:" + Thread.currentThread().getName() + "退出method1..");
    16             Thread.sleep(1000);
    17         } catch (InterruptedException e) {
    18             e.printStackTrace();
    19         } finally {
    20             
    21             lock.unlock();
    22         }
    23     }
    24 
    25     public static void main(String[] args) {
    26 
    27         final UseReentrantLock ur = new UseReentrantLock();
    28         Thread t1 = new Thread(new Runnable() {
    29             @Override
    30             public void run() {
    31                 ur.method1();
    32             }
    33         }, "t1");
    34 
    35         t1.start();
    36 
    37         Thread t2 = new Thread(new Runnable() {
    38             @Override
    39             public void run() {
    40                 ur.method1();
    41             }
    42         }, "t2");
    43 
    44         t2.start();
    45 
    46         try {
    47             Thread.sleep(10);
    48         } catch (InterruptedException e) {
    49             e.printStackTrace();
    50         }
    51         //System.out.println(ur.lock.getQueueLength());
    52     }
    53     
    54     
    55 }

    执行以后,可以发现,t1和t2是串行执行method1的

    3.ReentrantLock锁的等待与通知

    synchronized关键字里,有Object的wait()方法和notify()/notifyAll()方法进行多线程之间的工作协调。而同样的,Lock也有自己的等待/通知类,它就是Condition。这个Condition一定是针对某一把具体的锁的,就是说,只有有锁的基础之才会产生Condition

    代码实现:

     1 package lock020;
     2 
     3 import java.util.concurrent.locks.Condition;
     4 import java.util.concurrent.locks.Lock;
     5 import java.util.concurrent.locks.ReentrantLock;
     6 
     7 public class UseCondition {
     8 
     9     private Lock lock = new ReentrantLock();
    10     private Condition condition = lock.newCondition();
    11     
    12     public void method1(){
    13         try {
    14             lock.lock();
    15             System.out.println("当前线程:" + Thread.currentThread().getName() + "进入等待状态..");
    16             Thread.sleep(3000);
    17             System.out.println("当前线程:" + Thread.currentThread().getName() + "释放锁..");
    18             condition.await();    // Object wait,释放锁
    19             System.out.println("当前线程:" + Thread.currentThread().getName() +"继续执行...");
    20         } catch (Exception e) {
    21             e.printStackTrace();
    22         } finally {
    23             lock.unlock();
    24         }
    25     }
    26     
    27     public void method2(){
    28         try {
    29             lock.lock();
    30             System.out.println("当前线程:" + Thread.currentThread().getName() + "进入..");
    31             Thread.sleep(3000);
    32             System.out.println("当前线程:" + Thread.currentThread().getName() + "发出唤醒..");
    33             condition.signal();        //Object notify
    34         } catch (Exception e) {
    35             e.printStackTrace();
    36         } finally {
    37             lock.unlock();
    38         }
    39     }
    40     
    41     public static void main(String[] args) {
    42         
    43         final UseCondition uc = new UseCondition();
    44         Thread t1 = new Thread(new Runnable() {
    45             @Override
    46             public void run() {
    47                 uc.method1();
    48             }
    49         }, "t1");
    50         Thread t2 = new Thread(new Runnable() {
    51             @Override
    52             public void run() {
    53                 uc.method2();
    54             }
    55         }, "t2");
    56 
    57         t1.start();
    58         t2.start();
    59     }
    60     
    61     
    62     
    63 }

    以上代码,实现了wait/nofity的功能

    ps:不同的线程之间,可以用不同的Condition对象来进行通信。例如t1唤醒t2用 Condition1,t3唤醒t4用Condition2,这也是比wait/notify灵活的地方

    3.公平锁和非公平锁

    公平锁的作用就是严格按照线程启动的顺序来执行的,不允许其他线程插队执行的;而非公平锁是允许插队的。(默认是非公平锁)

    可以通过构造方法指定参数是ture(公平)或者false(非公平),一般说来,非公平锁比公平锁性能要好,因为公平锁要维护顺序

    4.ReentrantLock锁与synchronized的区别

    类别synchronizedLock
    存在层次 Java的关键字,在jvm层面上 是一个类
    锁的释放 1、以获取锁的线程执行完同步代码,释放锁 2、线程执行发生异常,jvm会让线程释放锁 在finally中必须释放锁,不然容易造成线程死锁
    锁的获取 假设A线程获得锁,B线程等待。如果A线程阻塞,B线程会一直等待 分情况而定,Lock有多个锁获取的方式,具体下面会说道,大致就是可以尝试获得锁,线程可以不用一直等待
    锁状态 无法判断 可以判断
    锁类型 可重入 不可中断 非公平 可重入 可判断 可公平(两者皆可)
    性能 少量同步 大量同步

    5.ReenTrantReadWriteLock(读写锁)

    核心其实就是实现读写分离。在高并发的情况下,尤其是读多写少的情况下,性能远高于重入锁

    之前的ReentrantLock和synchronized的使用时,同一时间内,只能一个线程访问被锁定的代码。读写锁不同,其本质是2个锁,即读锁和写锁。在读锁下,多个线程可以并发访问,但是在写锁下,只能串行访问

    口诀:读读共享,写写互斥,读写互斥

    代码示例:

     1 package lock021;
     2 
     3 import java.util.concurrent.locks.ReentrantReadWriteLock;
     4 import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
     5 import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
     6 
     7 public class UseReentrantReadWriteLock {
     8 
     9     private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    10     private ReadLock readLock = rwLock.readLock();
    11     private WriteLock writeLock = rwLock.writeLock();
    12     
    13     public void read(){
    14         try {
    15             readLock.lock();
    16             System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
    17             Thread.sleep(3000);
    18             System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
    19         } catch (Exception e) {
    20             e.printStackTrace();
    21         } finally {
    22             readLock.unlock();
    23         }
    24     }
    25     
    26     public void write(){
    27         try {
    28             writeLock.lock();
    29             System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
    30             Thread.sleep(3000);
    31             System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
    32         } catch (Exception e) {
    33             e.printStackTrace();
    34         } finally {
    35             writeLock.unlock();
    36         }
    37     }
    38     
    39     public static void main(String[] args) {
    40         
    41         final UseReentrantReadWriteLock urrw = new UseReentrantReadWriteLock();
    42         
    43         Thread tr1 = new Thread(new Runnable() {
    44             @Override
    45             public void run() {
    46                 urrw.read();
    47             }
    48         }, "t1");
    49         Thread tr2 = new Thread(new Runnable() {
    50             @Override
    51             public void run() {
    52                 urrw.read();
    53             }
    54         }, "t2");
    55         Thread tw3 = new Thread(new Runnable() {
    56             @Override
    57             public void run() {
    58                 urrw.write();
    59             }
    60         }, "t3");
    61         Thread tw4 = new Thread(new Runnable() {
    62             @Override
    63             public void run() {
    64                 urrw.write();
    65             }
    66         }, "t4");        
    67         
    68         tr1.start();
    69         tr2.start();
    70 
    71         tw3.start();
    72         tw4.start();
    73 
    74     }
    75 }

    模拟代码可发现:

    如果是都是读操作,基本是同时进行的

    如果有写操作,是要锁定的

    6.锁的优化

    (1)避免死锁

    (2)减小锁的持有时间

    (3)减小锁的粒度

    (4)锁的分离

    (5)尽量使用无锁的操作,如原子操作(Atomic类系列)、volatile关键字

    7.分布式锁的概念

    2台机器都部署了项目,显然,运行的jvm是不同的,如果t1线程在机器A,t2线程在机器B,同时要访问同一段锁定的代码块

    显然,jvm的锁机制是无法处理这种情况的,这时候要考虑第三方帮助实现,如zookkeeper

  • 相关阅读:
    AndEngine学习 : AnimatedSpritesExample(动画)
    AndEngine学习:PhysicsCollisionFiltering(有过滤器的碰撞检测)
    Android OpenGL ES和OpenGL一起学(一)绘制一个简单的矩形
    AndEngine学习:LevelLoaderExample(加载关卡)
    链式栈
    AndEngine学习:CollisionDetectionExample(碰撞检测)
    AndEngine学习 : BasePhysicsJoint(简单地和物理模型的联系)
    Use XML Schema Definition Tool to Generate the classes
    Ubuntu 配置基础开发环境
    Custom ConfigurationSection
  • 原文地址:https://www.cnblogs.com/billmiao/p/9872201.html
Copyright © 2020-2023  润新知