Lock锁介绍:

在java中可以使用 synchronized 来实现多线程下对象的同步访问,为了获得更加灵活使用场景、高效的性能,java还提供了Lock接口及其实现类ReentrantLock和读写锁 ReentrantReadWriteLock。

相比synchronized来实现同步,使用Lock实现同步主要有以下差异性:

 1、使用synchronized关键字时,锁的控制和释放是在synchronized同步代码块的开始和结束位置。而在使用Lock实现同步时,锁的获取和释放可以在不同的代码块、不同的方法中。这一点是基于使用者手动获取和释放锁的特性。

 2、Lock接口提供了试图获取锁的tryLock()方法,在调用tryLock()获取锁失败时返回false,这样线程可以执行其它的操作 而不至于使线程进入休眠。tryLock()方法可传入一个long型的时间参数,允许在一定的时间内来获取锁。

 3、Lock接口的实现类ReentrantReadWriteLock提供了读锁和写锁,允许多个线程获得读锁、而只能有一个线程获得写锁。读锁和写锁不能同时获得。实现了读和写的分离,这一点在需要并发读的应用中非常重要,如lucene允许多个线程读取索引数据进行查询但只能有一个线程负责索引数据的构建。

4、基于以上3点,lock来实现同步具备更好的性能。

Lock锁与条件同步:

与synchronized类似,Lock锁也可以实现条件同步。在java的concurrent包中提供了 Condition 接口及其实现类ConditionObject。

当满足一定条件时,调用Condition的await()方法使当前线程进入休眠状态进行等待。调用Condition的signalAll()方法唤醒因await()进入休眠的线程。

synchronized与条件同步博文中,我们使用synchronized实现了一个生产者-消费者模型,在这里,来试试使用Lock锁及其同步条件来实现同样的一个生产者-消费者模型:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Goods{
  private String goodsName;
  private Integer count=0;
  private Integer full;
  //获得lock对象
  private Lock lock=new ReentrantLock();
  //获得生产者等待队列对象
  private Condition productorCondition=lock.newCondition();
  //获得消费者等待队列对象
  private Condition customerCondition=lock.newCondition();
  public Goods(Integer full) {
    this.full = full;
  }
  public void setGoods(String goodsName){
    try{

      //使用锁实现同步,获取所得操作,当锁被其他线程占用时,当前线程将进入休眠  
      lock.lock();
      while (this.count==this.full){
        System.out.println("商品库存很多,快来购买哦");
        try {

          //满足条件时,线程休眠并释放锁。当调用 signalAll()时。线程唤醒并重新获得锁
          productorCondition.await();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }    
        }
      this.goodsName=goodsName;
      this.count++;
      System.out.println(Thread.currentThread().getName()+"生产"+this.toString());

      //唤醒因productorCondition.await()休眠的线程  
      customerCondition.signalAll();
    }finally {
      lock.unlock();//解锁
    }
    }
  public void getGoods(){
    try {
      lock.lock();
      while (this.count==0){
        System.out.println("商品正在生产中,亲稍等哦");
        try {
          customerCondition.await();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
       }
      this.count--;
      System.out.println(Thread.currentThread().getName()+"消费"+this.toString());

      //这个时候已经生产完了,生产者唤醒消费者进行消费
      productorCondition.signalAll();
    }finally {
      lock.unlock();
    }
  }

  @Override
  public String toString() {
    return "Goods{" +
      "goodsName='" + goodsName + '\'' +
      ", count=" + count +
      '}';
    }
}

class Productor implements Runnable{
  private Goods goods;

  public Productor(Goods goods) {
    this.goods = goods;
  }

  @Override
  public void run() {
    while (true){
      this.goods.setGoods("mac");
    }
  }
}

class Customer implements Runnable{
  private Goods goods;

  public Customer(Goods goods) {
    this.goods = goods;
  }

  @Override
  public void run() {
    while (true){
      this.goods.getGoods();
    }
  }
}

public class Test{
  public static void main(String[] args) {
    Goods goods=new Goods(20);
    Productor productor=new Productor(goods);
    Customer customer=new Customer(goods);
    List<Thread> list=new ArrayList<>();
    for(int i=0;i<5;i++){
      Thread thread=new Thread(productor,"生产者"+i);
      list.add(thread);
    }
    for(int i=0;i<10;i++){
      Thread thread=new Thread(customer,"消费者"+i);
      list.add(thread);
    }
    for(Thread thread:list){
      thread.start();
    }
  }
}

//控制台打印结果部分截图

总结:

不管是synchronized关键字还是Lock锁,都是用来在多线程的环境下对资源的同步访问进行控制,用以避免因多个线程对数据的并发读写造成的数据混乱问题。与synchronized不同的是,Lock锁实现同步时需要使用者手动控制锁的获取和释放,其灵活性使得可以实现更复杂的多线程同步和更高的性能,但同时,使用者一定要在获取锁后及时捕获代码运行过程中的异常并在finally代码块中释放锁。

线程高级篇-Lock锁实现生产者-消费者模型的更多相关文章

  1. 线程高级篇-Lock锁和Condition条件

    浅谈Synchronized: synchronized是Java的一个关键字,也就是Java语言内置的特性,如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,执行代码块时,其 ...

  2. python网络编程--进程(方法和通信),锁, 队列,生产者消费者模型

    1.进程 正在进行的一个过程或者说一个任务.负责执行任务的是cpu 进程(Process: 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在 ...

  3. java线程基础巩固---多线程下的生产者消费者模型,以及详细介绍notifyAll方法

    在上一次[http://www.cnblogs.com/webor2006/p/8419565.html]中演示了多Product多Consumer假死的情况,这次解决假死的情况来实现一个真正的多线程 ...

  4. POSIX信号量与互斥锁实现生产者消费者模型

    posix信号量 Link with -lpthread. sem_t *sem_open(const char *name, int oflag);//打开POSIX信号量 sem_t *sem_o ...

  5. Java多线程15:Queue、BlockingQueue以及利用BlockingQueue实现生产者/消费者模型

    Queue是什么 队列,是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的.无论使用哪种排序方式,队列的头都是调用remove()或poll()移 ...

  6. Python学习笔记——进阶篇【第九周】———线程、进程、协程篇(队列Queue和生产者消费者模型)

    Python之路,进程.线程.协程篇 本节内容 进程.与线程区别 cpu运行原理 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Ev ...

  7. python_way ,day11 线程,怎么写一个多线程?,队列,生产者消费者模型,线程锁,缓存(memcache,redis)

    python11 1.多线程原理 2.怎么写一个多线程? 3.队列 4.生产者消费者模型 5.线程锁 6.缓存 memcache redis 多线程原理 def f1(arg) print(arg) ...

  8. Python之路(第三十八篇) 并发编程:进程同步锁/互斥锁、信号量、事件、队列、生产者消费者模型

    一.进程锁(同步锁/互斥锁) 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的, 而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理. 例 ...

  9. day34 python学习 守护进程,线程,互斥锁,信号量,生产者消费者模型,

    六 守护线程 无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁 需要强调的是:运行完毕并非终止运行 #1.对主进程来说,运行完毕指的是主进程代码运行完毕 #2.对主线程来说,运行完 ...

随机推荐

  1. 学习笔记(7)- 基于LSTM的对话模型

    LSTM based Conversation Models 本文介绍一种会话语言模型,结合了局部.全局的上下文,以及参与者的角色. 问题提出者 倾向于用"任何人"."如 ...

  2. 【SSM 验证码】登录验证码

    LoginController /** * 登陆方法 */ @ResponseBody @RequestMapping("login2") public Map<String ...

  3. 【PAT甲级】1066 Root of AVL Tree (25 分)(AVL树建树模板)

    题意: 输入一个正整数N(<=20),接着输入N个结点的值,依次插入一颗AVL树,输出最终根结点的值. AAAAAccepted code: #define HAVE_STRUCT_TIMESP ...

  4. 洛谷 P1119 灾后重建(Floyd)

    嗯... 题目链接:https://www.luogu.org/problem/P1119 这道题是一个Floyd的很好的题目,在Floyd的基础上加一点优化: 中转点k在这里不能暴力枚举,否则会超时 ...

  5. 最全Python学习路线图【2020最新版】

    2020年最新的python学习大纲,专为python高薪打造另外很多人在学习Python的过程中,往往因为没有好的教程或者没人指导从而导致自己容易放弃,为此我建了个Python交流.裙 :一久武其而 ...

  6. linux--用户管理--useradd

    用户分类 1 root 超级管理员 2 系统用户 就是 某一个服务中 自动产生的用户 不是认为创建的,不能用于登录计算机 只是保证某一个服务的正常运行 比如数据库 3 普通用户 用户必须属于一个且只有 ...

  7. Codeforces Round #580 (Div. 2)D(思维,Floyd暴力最小环)

    #define HAVE_STRUCT_TIMESPEC#include<bits/stdc++.h>using namespace std;const int maxn=300;cons ...

  8. 记录一次Nginx使用第三方模块fair导致的线上故障排错

    一.问题 今天发现有一台服务器的内存飙升,然后有预警,立即排查,发现该服务内存使用达到了 2G ,询问开发,当天是否有活动,被告知没有,登陆 Pinpoint 发现该服务是有两台机器,并且所有的访问都 ...

  9. 123、Java面向对象之引用传递实例一

    01.代码如下: package TIANPAN; class Message { private int num = 10; // 定义int基本类型的属性 public Message(int n ...

  10. Scrapy 使用 LinkExtractor 提取链接和使用 Exporter 导出数据

    在爬取一个网站时,想要爬取的数据通常分布到多个页面中,每个页面包含一部分数据以及其他页面的链接,提取链接有使用 Selector 和使用 Linkextractor 两种方法. 1.使用Selecto ...