Lock在多线程模式下的应用

Lock多线程模式下的使用记住三个步骤

a.判断  while条件判断 多线程模式下一定是while

b.干活  执行业务代码

c.通知 唤醒下一个要运行的线程

还得记住 线程操作资源类,资源类要定义好 condition条件别忘了

1.一个初始值为0的变量 两个线程对其交替操作一个加1 一个减1 5轮(生产者 消费者模拟)
 

/**
 * 一个初始值为0的变量 两个线程对其交替操作
 * 一个加1 一个减1 来5轮
 */
public class ProdConsumer {
  public static void main(String[] args) {
    ShareDate shareDate = new ShareDate();
    new Thread(()->{
      try {
        for (int i = 1; i < 5; i++) {
          shareDate.increment();
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    },"aa").start();

    new Thread(()->{
      try {
        for (int i = 1; i < 5; i++) {
          shareDate.decrement();
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    },"bb").start();
  }
}

class ShareDate{
  private  int number = 0 ;
  private Lock lock = new ReentrantLock();
  private Condition condition = lock.newCondition();

  public void increment(){
    //判断
    lock.lock();
    try {
      while(number != 0){
        //等待  不能生产
        condition.await();
      }
      //干活
      number++;
      System.out.println(Thread.currentThread().getName()+"--"+number);
      condition.signalAll();
    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      lock.unlock();
    }
  }

  public void decrement() throws Exception{
    //判断
    lock.lock();
    try {
      while(number == 0){
        //等待  不能生产
        condition.await();
      }
      //干活
      number--;
      System.out.println(Thread.currentThread().getName()+"--"+number);
      condition.signalAll();
    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      lock.unlock();
    }
  }
}

2.生产者消费者加强版,BlockQueue

使用阻塞队列好处:我们不需要关系什么时候阻塞线程,什么时候唤醒线程

class MyResource{
    private volatile boolean flag = true;
    private AtomicInteger atomicInteger = new AtomicInteger();
    BlockingQueue<String> blockingQueue = null;

  public MyResource(BlockingQueue<String> blockingQueue) {
    this.blockingQueue = blockingQueue;
    System.out.println(blockingQueue.getClass().getName());
  }

  public void myProd() throws InterruptedException {
    String data = null;
    boolean retvalue;
    while(flag) {
      data = atomicInteger.incrementAndGet()+"";
      retvalue = blockingQueue.offer(data,2L, TimeUnit.SECONDS);
      if (retvalue) {
        System.out.println(Thread.currentThread().getName()+"插入队列:"+data+"成功");
      }else {
        System.out.println(Thread.currentThread().getName()+"插入队列:"+data+"失败");
      }
      TimeUnit.SECONDS.sleep(1);
    }
    System.out.println(Thread.currentThread().getName()+"生产结束");
  }

  public void myCons() throws InterruptedException {
    String result = null;
    //TimeUnit.SECONDS.sleep(10);
    while (flag){
      result = blockingQueue.poll(2L,TimeUnit.SECONDS);
      if(null == result || result.equalsIgnoreCase("")){
        flag = false;
        System.out.println(Thread.currentThread().getName()+"消费超时,退出");
        return;
      }
      System.out.println(Thread.currentThread().getName()+"消费队列"+result+"成功");
    }
  }

  public void stop() throws Exception{
    this.flag = false;
  }
}
public class ProdConsumer_BlockQueue {
  public static void main(String[] args) throws Exception{
  MyResource myResource = new MyResource(new ArrayBlockingQueue<>(3));
  new Thread(() ->{
    System.out.println(Thread.currentThread().getName()+"启动");
    try {
      myResource.myProd();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  },"prod").start();

    new Thread(() ->{
      System.out.println(Thread.currentThread().getName()+"启动");
      try {
        myResource.myCons();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    },"cons").start();

    TimeUnit.SECONDS.sleep(5);
    System.out.println();
    System.out.println("5秒后main叫停");
    myResource.stop();
  }
}

结果:

java.util.concurrent.ArrayBlockingQueue
prod启动
prod插入队列:1成功
cons启动
cons消费队列1成功
prod插入队列:2成功
cons消费队列2成功
prod插入队列:3成功
cons消费队列3成功
prod插入队列:4成功
cons消费队列4成功
prod插入队列:5成功
cons消费队列5成功

5秒后main叫停
prod生产结束
cons消费超时,退出

 思考下 消费者先不消费的场景 如下代码所示

class MyResource{
    private volatile boolean flag = true;
    private AtomicInteger atomicInteger = new AtomicInteger();
    BlockingQueue<String> blockingQueue = null;

  public MyResource(BlockingQueue<String> blockingQueue) {
    this.blockingQueue = blockingQueue;
    System.out.println(blockingQueue.getClass().getName());
  }

  public void myProd() throws InterruptedException {
    String data = null;
    boolean retvalue;
    while(flag) {
      data = atomicInteger.incrementAndGet()+"";
      retvalue = blockingQueue.offer(data,2L, TimeUnit.SECONDS);
      if (retvalue) {
        System.out.println(Thread.currentThread().getName()+"插入队列:"+data+"成功");
      }else {
        System.out.println(Thread.currentThread().getName()+"插入队列:"+data+"失败");
      }
      TimeUnit.SECONDS.sleep(1);
    }
    System.out.println(Thread.currentThread().getName()+"生产结束");
  }

  public void myCons() throws InterruptedException {
    String result = null;
    TimeUnit.SECONDS.sleep(10);
    while (flag){
      result = blockingQueue.poll(2L,TimeUnit.SECONDS);
      if(null == result || result.equalsIgnoreCase("")){
        flag = false;
        System.out.println(Thread.currentThread().getName()+"消费超时,退出");
        return;
      }
      System.out.println(Thread.currentThread().getName()+"消费队列"+result+"成功");
    }
  }

  public void stop() throws Exception{
    this.flag = false;
  }
}
public class ProdConsumer_BlockQueue {
  public static void main(String[] args) throws Exception{
  MyResource myResource = new MyResource(new ArrayBlockingQueue<>(3));
  new Thread(() ->{
    System.out.println(Thread.currentThread().getName()+"启动");
    try {
      myResource.myProd();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  },"prod").start();

    new Thread(() ->{
      System.out.println(Thread.currentThread().getName()+"启动");
      try {
        myResource.myCons();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    },"cons").start();

    TimeUnit.SECONDS.sleep(20);
    System.out.println();
    System.out.println("20秒后main叫停");
    myResource.stop();
  }
}

结果

java.util.concurrent.ArrayBlockingQueue
prod启动
prod插入队列:1成功
cons启动
prod插入队列:2成功
prod插入队列:3成功
prod插入队列:4失败
prod插入队列:5失败
cons消费队列1成功
cons消费队列2成功
cons消费队列3成功
cons消费队列6成功
prod插入队列:6成功
prod插入队列:7成功
cons消费队列7成功
prod插入队列:8成功
cons消费队列8成功
prod插入队列:9成功
cons消费队列9成功
prod插入队列:10成功
cons消费队列10成功
prod插入队列:11成功
cons消费队列11成功
prod插入队列:12成功
cons消费队列12成功
prod插入队列:13成功
cons消费队列13成功
prod插入队列:14成功
cons消费队列14成功
prod插入队列:15成功
cons消费队列15成功

20秒后main叫停
prod生产结束
cons消费超时,退出

 

3.实现AA--BB--CC三个线程启动  要求

AA打印5次后BB打印10次 cc打印15次 紧接着 AA打印5次后BB打印10次 cc打印15次

来十轮

package com.example.starter;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//线程操作资源类
class ShareResoucre{
  private int number = 1;
  private Lock lock = new ReentrantLock();
  private Condition c1 = lock.newCondition();
  private Condition c2 = lock.newCondition();
  private Condition c3 = lock.newCondition();

  public void prints5(){
    lock.lock();
    try {
      //判断
      while(number != 1){
        c1.await();
      }
      //干活
      for (int i = 0; i < 5; i++) {
        System.out.println(Thread.currentThread().getName()+"--"+i);
      }
      // //通知
      number = 2;
      c2.signal();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }

  public void prints10(){
    lock.lock();
    try {
      //判断
      while(number != 2){
        c2.await();
      }
      //干活
      for (int i = 0; i < 10; i++) {
        System.out.println(Thread.currentThread().getName()+"--"+i);
      }
      // //通知
      number = 3;
      c3.signal();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }

  public void prints15(){
    lock.lock();
    try {
      //判断
      while(number != 3){
        c3.await();
      }
      //干活
      for (int i = 0; i < 15; i++) {
        System.out.println(Thread.currentThread().getName()+"--"+i);
      }
      // //通知
      number = 1;
      c1.signal();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }
}
public class SynAndReentrantLockDemo {
  public static void main(String[] args) {
    ShareResoucre shareResoucre = new ShareResoucre();
    for (int i = 0; i < 10; i++) {
      new Thread(() ->{
        shareResoucre.prints5();
      },"AA").start();

      new Thread(() ->{
        shareResoucre.prints10();
      },"BB").start();

      new Thread(() ->{
        shareResoucre.prints15();
      },"CC").start();
    }
  }
}

4.尝试使用如下方式实现步骤3的需求

此方式会造成死循环,因为使用同一个lock锁对象,进入某个方法时  number不满足条件将会无限循环 不释放锁

//线程操作资源类
class ShareResoucre{
  private volatile  int number = 1;
  private Lock lock = new ReentrantLock();

  private Condition c1 = lock.newCondition();
  private Condition c2 = lock.newCondition();
  private Condition c3 = lock.newCondition();

  public void prints5(){
    lock.lock();
    try {
      //System.out.println("prints5");
      //判断
      while(number != 1){
        Thread.sleep(3);
       // c1.await();
      }
      //干活
      for (int i = 0; i < 5; i++) {
        System.out.println(Thread.currentThread().getName()+"--"+i);
      }
      // //通知
      number = 2;
      //c2.signal();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }

  public void prints10(){
    lock.lock();
    try {
      //判断
      while(number != 2){
       // c2.await();
      }
      //干活
      for (int i = 0; i < 10; i++) {
        System.out.println(Thread.currentThread().getName()+"--"+i);
      }
      // //通知
      number = 3;
      //c3.signal();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }

  public void prints15(){
    lock.lock();
    try {
      //判断
      while(number != 3){
        //c3.await();
      }
      //干活
      for (int i = 0; i < 15; i++) {
        System.out.println(Thread.currentThread().getName()+"--"+i);
      }
      // //通知
      number = 1;
      //c1.signal();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }
}
public class SynAndReentrantLockDemo {
  public static void main(String[] args) {
    ShareResoucre shareResoucre = new ShareResoucre();
    for (int i = 0; i < 10; i++) {
      new Thread(() ->{
        shareResoucre.prints5();
      },"AA").start();

      new Thread(() ->{
        shareResoucre.prints10();
      },"BB").start();

      new Thread(() ->{
        shareResoucre.prints15();
      },"CC").start();
    }
  }
}

5.可以使用如下方式优化,创建三个锁对象

//线程操作资源类
class ShareResoucre{
  private volatile  int number = 1;
  private Lock lock1 = new ReentrantLock();
  private Lock lock2 = new ReentrantLock();
  private Lock lock3 = new ReentrantLock();
/*  private Condition c1 = lock.newCondition();
  private Condition c2 = lock.newCondition();
  private Condition c3 = lock.newCondition();*/

  public void prints5(){
    lock1.lock();
    try {
      //判断
      while(number != 1){
        Thread.sleep(3);
       // c1.await();
      }
      //干活
      for (int i = 0; i < 5; i++) {
        System.out.println(Thread.currentThread().getName()+"--"+i);
      }
      // //通知
      number = 2;
      //c2.signal();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      lock1.unlock();
    }
  }

  public void prints10(){
    lock2.lock();
    try {
      //判断
      while(number != 2){
       // c2.await();
      }
      //干活
      for (int i = 0; i < 10; i++) {
        System.out.println(Thread.currentThread().getName()+"--"+i);
      }
      // //通知
      number = 3;
      //c3.signal();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      lock2.unlock();
    }
  }

  public void prints15(){
    lock3.lock();
    try {
      //判断
      while(number != 3){
        //c3.await();
      }
      //干活
      for (int i = 0; i < 15; i++) {
        System.out.println(Thread.currentThread().getName()+"--"+i);
      }
      // //通知
      number = 1;
      //c1.signal();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      lock3.unlock();
    }
  }
}
public class SynAndReentrantLockDemo {
  public static void main(String[] args) {
    ShareResoucre shareResoucre = new ShareResoucre();
    for (int i = 0; i < 10; i++) {
      new Thread(() ->{
        shareResoucre.prints5();
      },"AA").start();

      new Thread(() ->{
        shareResoucre.prints10();
      },"BB").start();

      new Thread(() ->{
        shareResoucre.prints15();
      },"CC").start();
    }
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值