JUC并发编程(一): Lock锁+新版生产者消费者写法

1. 什么是JUC

JUC是Java.util.concurrent包的简称,是Java提供用来支持高并发的工具类。
在这里插入图片描述

2.进程和线程回顾

进程/线程是什么?

进程:正在运行的程序,资源分配的最小单位
线程:CPU调度的最小单位
一个进程可能包含多个线程,至少包含一个。Java main,GC线程。

并发/并行是什么?

并发:多线程操作一个资源类,快速交替过程。
并行:多核CPU,同时处理多个线程。

你吃饭,吃到一半,电话来了,3种情况
1.吃完再去接电话(单线程)
2.先接电话再吃(交替,并发)
3.边吃边接电话(并发)

一个CPU的电脑不能并发执行任务
并发编程的主要目的,充分利用CPU的资源,提高性能

线程的状态

线程的状态6种

public enum State {
 
    NEW,

    RUNNABLE,

    BLOCKED,

    WAITING, // 等待

    TIMED_WAITING, // 延时等待 

    TERMINATED; //
}

wait/sleep的区别

1.类
wait -> Object
sleep -> Thread, 谁调用的sleep方法就是谁睡觉!
例如:A调用了B的sleep方法,实际上就是A睡觉。

2.释放锁
sleep抱着锁睡觉
wait会释放锁

3.使用范围不同
wait、notify、notifyAll只能在同步方法中或者同步代码块中;
sleep可以在任意地方使用;

4.异常
sleep,必须捕获异常!
wait,不需要捕获异常!

3.Lock锁

传统的synchronized

package com.coding.demo01;

import java.util.TimerTask;

/**
 *线程  操作(调用资源类暴露的方法) 资源类
 */
public class SaleTicketTest1 {
    public static void main(String[] args) {

        // 资源类
        final SaleTicket saleTicket = new SaleTicket();

        new Thread(new Runnable() {
            public void run() {
                for (int i = 1; i < 40; i++) {
                    saleTicket.saleTicket();
                }
            }
        }, "A").start();

        new Thread(new Runnable() {
            public void run() {
                for (int i = 1; i < 40; i++) {
                    saleTicket.saleTicket();
                }
            }
        }, "B").start();

        new Thread(new Runnable() {
            public void run() {
                for (int i = 1; i < 40; i++) {
                    saleTicket.saleTicket();
                }
            }
        }, "C").start();

    }
}

// 属性,和方法  高内聚
class SaleTicket{ //资源类
    private int number = 30;

    // 卖票方法
    public synchronized void saleTicket(){
        if (number>0){
            System.out.println(Thread.currentThread().getName()+"卖出第"+ (number--) +"还剩下:"+number+"张票");
        }
    }

}

使用juc.locks包下的类操作Lock锁+Lambda表达式
在这里插入图片描述

package com.coding.demo01;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SaleTicketTest2 {
    public static void main(String[] args) {

        // 并发: 多线线程操作同一个资源类
        // 资源类
        SaleTicket2 saleTicket = new SaleTicket2();

        // lambda表达式、链式编程、流式计算!
        //  lambda表达式,() -> {} 自动推断类型

        // IDEA 一定要设置 JDK 版本为 1.8 版本
        new Thread(() -> {
            for (int i = 1; i < 40; i++) saleTicket.saleTicket();
        }, "A").start();

        new Thread(() -> {
            for (int i = 1; i < 40; i++) saleTicket.saleTicket();
        }, "B").start();

        new Thread(() -> {
            for (int i = 1; i < 40; i++) saleTicket.saleTicket();
        }, "C").start();

    }
}

// 属性,和方法  高内聚
class SaleTicket2 { //资源类
    private int number = 30;

    // 锁LOCK
    private Lock lock = new ReentrantLock(); // 可重入

    // 卖票方法
    public void saleTicket() {
        lock.lock(); // 加锁
        try {
            // 业务代码
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出第" + (number--) + "还剩下:" + number + "张票");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock(); // 解锁
        }

    }

}

synchronized和lock区别(自动档 手动挡)

1.synchronized关键字,Java内置的。lock是一个Java类
2.synchronized无法判断是否获取锁,lock可以判断是否获得锁
3.synchronized锁会自动释放!lock需要手动在finally释放锁,如果不释放锁,就会死锁。
4.synchronized线程1阻塞 线程2永久等待下去。lock可以lock.tryLock();//尝试获取锁,如果获取不到锁,可以结束等待
5.synchronizd可重入,不可中断,非公平得,Lock锁,可重入、可以判断、可以公平!

可重入:一个房子如果只有一个大门,只要拿到大门的钥匙,就可以进入卧室,厨房,厕所,不需要额外再获取钥匙。

公平:排队,必须先来后到!
非公平:可以插队~

4.生产者和消费者

线程间得通信、无法通信,调度线程

生产者和消费者synchronized版

package com.coding.demo02;

/**
 * 题目:现在两个线程,操作一个初始值为0的变量
 *       一个线程 + 1, 一个线程 -1。判断什么时候+1,什么时候-1
 *       交替10 次
 *   生产者消费者模式:判断  干活  通知
 */
public class A {

    public static void main(String[] args) {
        Data data = new Data();

        new Thread(()->{
            for (int i = 1; i <= 10; i++) {
                try {
                    data.increment();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },"A").start();

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

    }

}


// 资源类  属性,方法
class Data{
    private int num = 0;

    // +1
    public synchronized void increment() throws Exception{
        //判断
        if (num!=0){
            this.wait();
        }
        // 干活
        num++;
        System.out.println(Thread.currentThread().getName()+"\t"+num);
        // 通知
        this.notifyAll();
    }

    // -1
    public synchronized void decrement() throws Exception{
        // 判断
        if (num==0){
            this.wait();
        }
        // 干活
        num--;
        System.out.println(Thread.currentThread().getName()+"\t"+num);
        // 通知
        this.notifyAll();
    }

}

问题升级:防止虚假唤醒,4个线程,两个加,两个减

在这里插入图片描述

package com.coding.demo02;

public class A {

    public static void main(String[] args) {
        Data data = new Data();

        new Thread(()->{
            for (int i = 1; i <= 10; i++) {
                try {
                    data.increment();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },"A").start();

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

        new Thread(()->{
            for (int i = 1; i <= 10; i++) {
                try {
                    data.increment();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },"C").start();

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

    }

}


// 资源类  属性,方法
class Data{
    private int num = 0;

    // +1
    public synchronized void increment() throws Exception{
        //判断  if 只判断了一次,  0  1  0   1   
        while (num!=0){    
            this.wait();
        }
        // 干活
        num++; 
        System.out.println(Thread.currentThread().getName()+"\t"+num);
        // 通知
        this.notifyAll();
    }

    // -1
    public synchronized void decrement() throws Exception{
        // 判断
        while (num==0){
            this.wait(); //0
        }
        // 干活
        num--;
        System.out.println(Thread.currentThread().getName()+"\t"+num);
        // 通知
        this.notifyAll();
    }

}

传统的,JUC!

新版生产者和消费者写法

在这里插入图片描述
任何一个新技术的出现,一定不仅仅是换了个马甲在这里插入图片描述

package com.coding.demo02;

import sun.awt.SunHints;

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

// lock版生产者消费者
public class B {


    public static void main(String[] args) {
        // 新版
        Data2 data = new Data2();

        new Thread(()->{
            for (int i = 1; i <= 10; i++) {
                try {
                    data.increment();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },"A").start();

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

        new Thread(()->{
            for (int i = 1; i <= 10; i++) {
                try {
                    data.increment();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },"C").start();

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

    }

}

// 资源类  属性,方法
class Data2{
    private int num = 0;
    // 定义锁
    Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    // +1
    public void increment() throws Exception{

        // 加锁
        lock.lock();

        try {
            //判断
            while (num!=0){
                condition.await(); //等待
            }
            // 干活
            num++;
            System.out.println(Thread.currentThread().getName()+"\t"+num);
            // 通知
            condition.signalAll();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 解锁
            lock.unlock();
        }
    }

    // -1
    public void decrement() throws Exception{


        // 加锁
        lock.lock();
        try {
            // 判断
            while (num==0){
                condition.await(); //等待
            }
            // 干活
            num--;
            System.out.println(Thread.currentThread().getName()+"\t"+num);
            // 通知
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 解锁
            lock.unlock();
        }
    }

}

精确通知顺序访问 Condition

在这里插入图片描述

package com.coding.demo02;

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

/**
 *  多个线程启动  A -- B -- C
 *  三个线程依次打印
 *  A  5次
 *  B  10次
 *  C  15次
 *  依次循环
 *
 *  精确通知线程消费
 */
public class C {

    public static void main(String[] args) {
        Data3 data = new Data3();

        // 线程操作资源类
        new Thread(()->{
            for (int i = 1; i <= 10; i++) {
                data.print5();
            }
        },"A").start();

        new Thread(()->{
            for (int i = 1; i <= 10; i++) {
                data.print10();
            }
        },"B").start();

        new Thread(()->{
            for (int i = 1; i <= 10; i++) {
                data.print15();
            }
        },"C").start();

    }

}


// 资源类  属性,方法
class Data3{
    private int num = 1; // A1   B2   C3
    // 定义锁
    Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition(); //3个判断,交替执行 A--B--C--A
    private Condition condition2 = lock.newCondition(); //3个判断,交替执行 A--B--C--A
    private Condition condition3 = lock.newCondition(); //3个判断,交替执行 A--B--C--A

    // 3个方法、作业,合3为1
    // +1
    public void print5(){
        // 加锁
        lock.lock();
        try {
            //判断
            while (num!=1){
                condition1.await(); //等待
            }
            // 干活
            for (int i = 1; i <=5 ; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+i);
            }

            // 第一个线程通知第二个线程,第二个线程通知第三个....  计数器
            num=2;
            // 通知第二个线程干活,指定谁干活
            condition2.signal();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 解锁
            lock.unlock();
        }
    }

    public void print10() {
        // 加锁
        lock.lock();
        try {
            //判断
            while (num!=2){
                condition2.await(); //等待
            }
            // 干活
            for (int i = 1; i <=10 ; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+i);
            }
            // 第一个线程通知第二个线程,第二个线程通知第三个....  计数器
            num=3;
            // 通知第二个线程干活,指定谁干活
            condition3.signal();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 解锁
            lock.unlock();
        }
    }

    public void print15() {
        // 加锁
        lock.lock();
        try {
            //判断
            while (num!=3){
                condition3.await(); //等待
            }
            // 干活 = 业务代码
            for (int i = 1; i <=15 ; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+i);
            }

            num=1;
            condition1.signal();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 解锁
            lock.unlock();
        }
    }


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值