博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java并发编程--3.Lock
阅读量:5248 次
发布时间:2019-06-14

本文共 8376 字,大约阅读时间需要 27 分钟。

Lock接口

它提供3个常用的锁

lock() : 获不到锁就就一直阻塞trylock() :获不到锁就立刻放回 或者 定时的,轮询的获取锁 lockInterruptibly() : 获不到锁时阻塞,但可接受中断信号后退出阻塞状态

ReentrantLock

实现机制

基于冲突的乐观并发策略:

如果共享数据被争用,产生了冲突,那就再进行其他的补偿措施,比如说定时的获取锁,直到成功;不需要把线程挂起,也称为非阻塞的同步

公平性

公平: 多个线程在等待同一个锁时,必须按照申请锁的时间顺序排队等待

非公平: 在锁释放时,任何一个等待锁的线程都有机会获得锁,ReentrantLock构造方法,默然是非公平的

什么时候使用

当你需要可定时的和可中断的锁操作,公平队列,或者非块结构的锁,否则请使用synchronized

可中断的例子

public class MyReentrantLock {    private ReentrantLock lock = new ReentrantLock();            public void write() {          lock.lock();          try {              long startTime = System.currentTimeMillis();              System.out.println("开始往这个buff写入数据…");              for (;;)// 模拟要处理很长时间                  {                  if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE) {                      break;                  }              }              System.out.println("终于写完了");          } finally {              lock.unlock();          }      }        public void read() throws InterruptedException {          lock.lockInterruptibly();// 注意这里,可以响应中断              try {              System.out.println("从这个buff读数据");          } finally {              lock.unlock();          }      }        public static void main(String args[]) {          MyReentrantLock buff = new MyReentrantLock();            final Writer2 writer = new Writer2(buff);          final Reader2 reader = new Reader2(buff);            writer.start();          reader.start();            new Thread(new Runnable() {                @Override              public void run() {                  long start = System.currentTimeMillis();                  for (;;) {                      if (System.currentTimeMillis() - start > 5000) {                          System.out.println("不等了,尝试中断");                          reader.interrupt();  //此处中断读操作                          break;                      }                  }              }          }).start();        }  }    class Reader2 extends Thread {        private MyReentrantLock buff;        public Reader2(MyReentrantLock buff) {          this.buff = buff;      }        @Override      public void run() {            try {              buff.read();//可以收到中断的异常,从而有效退出              } catch (InterruptedException e) {              System.out.println("我不读了");          }            System.out.println("读结束");        }  }    class Writer2 extends Thread {        private MyReentrantLock buff;        public Writer2(MyReentrantLock buff) {          this.buff = buff;      }        @Override      public void run() {          buff.write();      }  }

控制台输出:

开始往这个buff写入数据…不等了,尝试中断我不读了读结束

ReentrantReadWriteLock读写锁

特点

互斥:它使得读写操作互斥,读读操作不互斥锁降级:写线程获取写入锁后可以获取读取锁,然后释放写入锁,这样就从写入锁变成了读取锁

少写多读的例子

public class MyReadWriteLock {    public static void main(String[] args) {        PricesInfo pricesInfo = new PricesInfo();        Writer writer=new Writer(pricesInfo);        Reader read =  new Reader(pricesInfo);                //写线程        Thread tw=new Thread(writer);        tw.start();                //多个读线程        for (int i=0; i<5; i++){            Thread tr=new Thread(read);            tr.start();        }     }}//读线程class Reader implements Runnable{    private PricesInfo pricesInfo;        public Reader(PricesInfo pricesInfo){        this.pricesInfo = pricesInfo;    }    @Override    public void run() {        pricesInfo.getPrice();    }}//写线程class Writer implements Runnable{    private PricesInfo pricesInfo;    public Writer(PricesInfo pricesInfo){        this.pricesInfo = pricesInfo;    }        @Override    public void run() {        pricesInfo.setPrice(Math.random()*10);            }}//数据实体class PricesInfo {    private double price;        private ReadWriteLock  lock = new ReentrantReadWriteLock();        public PricesInfo(){    }        //读锁    public void getPrice(){        lock.readLock().lock();        System.out.println(Thread.currentThread().getName()+ " : in read*****************************");        System.out.println(Thread.currentThread().getName()+ ": 读取数据= " + price);        lock.readLock().unlock();    }        //写锁    public void setPrice(double price){        lock.writeLock().lock();         try {            System.out.println(Thread.currentThread().getName()+ " :in Writer==============================================");            Thread.sleep(1000);            this.price = price;            System.out.println(Thread.currentThread().getName()+ ":写入数据= " + price);        } catch (InterruptedException e) {            e.printStackTrace();        }finally {            lock.writeLock().unlock();        }    }}

控制台输出:

Thread-0 :in Writer==============================================Thread-0:写入数据= 3.5843085966236266Thread-3 : in read*****************************Thread-3: 读取数据= 3.5843085966236266......

 Condition条件变量

通过ReentrantLock的newCondition()得到Condition对象,它用await()替换wait(),用signal()替换 notify(),用signalAll()替换notifyAll(), 实现线程间的通信;

如果是公平锁,与Condition关联的任务,以FIFO的形式获取锁,否则的话,是随机获取锁;

消费者和生产者的例子

public class MyCondition{      public static void main(String args[]){          Info info = new Info();                 //启动生产者        Producer pro = new Producer(info) ;         new Thread(pro).start() ;                  try{              Thread.sleep(100) ;          }catch(InterruptedException e){              e.printStackTrace() ;          }            //启动消费者        Consumer con = new Consumer(info) ;        new Thread(con).start() ;      }  }  class Info{ // 定义信息类      private String name = null;    private String content = null ;    private boolean flag = true ;   // true生产, false消费        private Lock lock = new ReentrantLock();        private Condition condition = lock.newCondition(); //产生一个Condition对象         public  void set(String name,String content){          lock.lock();          try{              while(!flag){                  condition.await() ;              }                          this.setName(name) ;                           Thread.sleep(300) ;                          this.setContent(content) ;             flag  = false ; // 改变标志位,表示可以取走                          System.out.println("生产者: " + this.getName() +  " --> " + this.getContent()) ;                        condition.signal();          }catch(InterruptedException e){              e.printStackTrace() ;          }finally{              lock.unlock();          }      }        public void get(){          lock.lock();          try{              while(flag){                  condition.await() ;              }                             Thread.sleep(300) ;                          System.out.println("消费者: " + this.getName() +  " --> " + this.getContent()) ;                         flag  = true ;  // 改变标志位,表示可以生产                         condition.signal();          }catch(InterruptedException e){              e.printStackTrace() ;          }finally{              lock.unlock();          }      }        public void setName(String name){          this.name = name ;      }      public void setContent(String content){          this.content = content ;      }      public String getName(){          return this.name ;      }      public String getContent(){          return this.content ;      }  }  /**生产者线程 */class Producer implements Runnable{       private Info info = null ;      // 保存Info引用          public Producer(Info info){          this.info = info ;      }          public void run(){          boolean flag = true ;   // 定义标记位          for(int i=0;i<10;i++){              if(flag){                  this.info.set("姓名--1","内容--1") ;                    flag = false ;              }else{                  this.info.set("姓名--2","内容--2") ;                     flag = true ;              }          }      }  } /**消费者线程 */class Consumer implements Runnable{      private Info info = null ;          public Consumer(Info info){          this.info = info ;      }      public void run(){         for(int i=0;i<10;i++){              this.info.get() ;          }      }  }

AQS 和 CAS

AQS : JUC基础类

state : 获取锁的标志

 

NOde{} : 获取锁的线程

SHARED : 共享锁
EXCLUSIVE : 互斥锁

 

CLH同步队列

LockSupport.park() 和 LockSupport.unpark() :阻塞和唤醒

CAS: JUC基础理论

对内存中共享数据进行操作的指令集, 自动更新共享数据, 代替了锁

内存值V,旧的预期值A,要修改的新值B。当且仅A和内存值V相同时,将内存值V修改为B,否则什么都不做

ABA问题

因为CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A

 

转载于:https://www.cnblogs.com/liuconglin/p/6693825.html

你可能感兴趣的文章
C++循环单链表删除连续相邻重复值
查看>>
渣渣小本求职复习之路每天一博客系列——Java基础(3)
查看>>
Jmeter接口压力测试,Java.net.BindException: Address already in use: connect
查看>>
ASP.NET使网页弹出窗口不再困难
查看>>
Leetcode Balanced Binary Tree
查看>>
Leetcode 92. Reverse Linked List II
查看>>
windown快速安装xgboost
查看>>
Linux上安装Libssh2
查看>>
九.python面向对象(双下方法内置方法)
查看>>
go:channel(未完)
查看>>
[JS]递归对象或数组
查看>>
LeetCode(17) - Letter Combinations of a Phone Number
查看>>
Linux查找命令对比(find、locate、whereis、which、type、grep)
查看>>
路由器外接硬盘做nas可行吗?
查看>>
python:从迭代器,到生成器,再到协程的示例代码
查看>>
Java多线程系列——原子类的实现(CAS算法)
查看>>
在Ubuntu下配置Apache多域名服务器
查看>>
多线程《三》进程与线程的区别
查看>>
linux sed命令
查看>>
LeetCode 160. Intersection of Two Linked Lists
查看>>