JavaSE之JUC基础

Juc并发编程

1、什么是JUC

JUC:Java原生的并发包,和一些常用的工具类!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ndmlujtt-1590912119920)(Juc并发编程课堂笔记.assets/image-20200301212335672.png)]

2、线程基础知识回顾

什么是进程和线程?

进程:idea.exe

线程:打字、自动保存…

一个进程可以包含多个线程,一个进程至少有一个线程! Java程序至少有两个线程: GC、Main

并发、并行

并发:多个线程操作同一个资源,交替执行的过程!

并行:多个线程同时执行!只有在多核CPU下才能完成!

所以我们使用多线程或者并发编程的目的:提高效率,让CPU一直工作,达到最高处理性能!

线程有几种状态

线程有 6 种状态,面向源码学习!

public enum State {
    // java能够创建线程吗? 不能!只能通过native调用本地方法实现
 	// 新建
    NEW,

    // 运行
    RUNNABLE,

    // 阻塞
    BLOCKED,

    // 等待
    WAITING,

    // 延时等待
    TIMED_WAITING,

    // 终止!
    TERMINATED;
}

wait/Sleep区别

1、类不同!

wait : Obejct 类     Sleep Thread

在juc编程中,线程休眠怎么实现!Thread.Sleep
     // 时间单位
     TimeUnit.SECONDS.sleep(3);

2、会不会释放资源!

  • sleep:抱着锁睡得,不会释放锁!

  • wait :会释放锁!

3、使用的范围是不同的;

wait 和 notify 是一组,一般在线程通信的时候使用!

sleep 就是一个单独的方法,在哪里都可以用!

4、关于异常;

sleep 需要捕获异常!

3、Lock锁

synchronized 传统的方式!

代码:

package com.coding.demo01;

// 传统的 Synchronized
// Synchronized 方法 和 Synchronized 块

/*
 * 1、架构:高内聚,低耦合
 * 2、套路:线程操作资源类,资源类是单独的
 */
public class Demo01 {
    public static void main(String[] args) throws InterruptedException {
        // 1、新建资源类
        Ticket ticket = new Ticket();

        // 2、线程操纵资源类
        new Thread(new Runnable() {
            public void run() {
                for (int i = 1; i <=40; i++) {
                    ticket.saleTicket();
                }
            }
        },"A").start();


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

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

    }
}

// 单独的资源类,属性和方法!
// 这样才能实现复用!
class Ticket{

    private int number = 30;

    // 同步锁,厕所 =>close=>
    // synchronized 这是一个关键字
    public synchronized void saleTicket(){
        if (number>0){
            System.out.println(Thread.currentThread().getName() + "卖出第"+(number--)+"票,还剩:"+number);
        }
    }

}

问题:

Lock 锁

代码:

package com.coding.demo01;

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

/*
 * JUC之后的操作
 * Lock锁 + lambda表达式!
 */
public class Demo02 {
    public static void main(String[] args) {
        // 1、新建资源类
        Ticket2 ticket = new Ticket2();
        // 2、线程操作资源类 , 所有的函数式接口都可以用 lambda表达式简化!
        // lambda表达式 (参数)->{具体的代码}
        new Thread(()->{for (int i = 1; i <= 40 ; i++) ticket.saleTicket();},"A").start();
        new Thread(()->{for (int i = 1; i <= 40 ; i++) ticket.saleTicket();},"B").start();
        new Thread(()->{for (int i = 1; i <= 40 ; i++) ticket.saleTicket();},"C").start();

    }
}


// 依旧是一个资源类
class Ticket2{
    // 使用Lock,它是一个对象
    // ReentrantLock 可重入锁:回家:大门 (卧室门,厕所门...)
    // ReentrantLock 默认是非公平锁!
    // 非公平锁: 不公平 (插队,后面的线程可以插队)
    // 公平锁: 公平(只能排队,后面的线程无法插队)
    private Lock lock = new ReentrantLock();

    private int number = 30;

    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 是一个关键字、Lock 是一个对象

2、Synchronized 无法尝试获取锁,Lock 可以尝试获取锁,判断;

3、Synchronized 会自动释放锁(a线程执行完毕,b如果异常了,也会释放锁),lock锁是手动释放锁!如果你不释放就会死锁。

4、Synchronized (线程A(获得锁,如果阻塞),线程B(等待,一直等待);)lock,可以尝试获取锁,失败了之后就放弃

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dp5DJE2d-1590912119924)(Juc并发编程课堂笔记.assets/image-20200301220037357.png)]

5、Synchronized 一定是非公平的,但是 Lock 锁可以是公平的,通过参数设置;

6、代码量特别大的时候,我们一般使用Lock实现精准控制,Synchronized 适合代码量比较小的同步问题;

4、生产者消费者问题

面试手写题:单例模式、排序算法、死锁、生产者消费者

线程和线程之间本来是不能通信的,但是有时候我们需要线程之间可以协调操作:

Synchronized 普通版

package com.coding.demo01;

// Synchronized 版
/*
目的: 有两个线程:A  B ,还有一个值初始为0,
       实现两个线程交替执行,对该变量 + 1,-1;交替10次
 */
public class Demo03 {
    public static void main(String[] args) {
        Data data = new Data();

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

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


    }
}

// 资源类
// 线程之间的通信: 判断  执行  通知
class Data{

    private int number = 0;

    // +1
    public synchronized void increment() throws InterruptedException {
        if (number!=0){ // 判断是否需要等待
            this.wait();
        }
        number++; // 执行
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        // 通知
        this.notifyAll(); //唤醒所有线程
    }

    // -1
    public synchronized void decrement() throws InterruptedException {
        if (number==0){ // 判断是否需要等待
            this.wait();
        }
        number--; // 执行
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        // 通知
        this.notifyAll(); //唤醒所有线程
    }

}

四条线程可以实现交替吗?不能,会产生虚假唤醒问题!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fDRcxwrH-1590912119925)(Juc并发编程课堂笔记.assets/image-20200301221345082.png)]

注意if 和 while的区别:

package com.coding.demo01;

// Synchronized 版
/*
目的: 有两个线程:A  B ,还有一个值初始为0,
       实现两个线程交替执行,对该变量 + 1,-1;交替10次
       
传统的 wait 和 notify方法不能实现精准唤醒通知!
 */
public class Demo03 {
    public static void main(String[] args) {
        Data data = new Data();

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

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


    }
}

// 资源类
// 线程之间的通信: 判断  执行  通知
class Data{

    private int number = 0;

    // +1
    public synchronized void increment() throws InterruptedException {
        while (number!=0){ // 判断是否需要等待
            this.wait();
        }
        number++; // 执行
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        // 通知
        this.notifyAll(); //唤醒所有线程
    }

    // -1
    public synchronized void decrement() throws InterruptedException {
        while (number==0){ // 判断是否需要等待
            this.wait();
        }
        number--; // 执行
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        // 通知
        this.notifyAll(); //唤醒所有线程
    }

}

新版的写法 JUC 挂钩!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5EnyBF0s-1590912119929)(Juc并发编程课堂笔记.assets/image-20200301221901605.png)]
在这里插入图片描述

package JUC;

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

/*
实现线程交替执行!
主要的实现目标:精准的唤醒线程!
    三个线程:A B C
    三个方法:A p5  B p10   C p15 依次循环
 */
public class ConditionLearn {
    public static void main(String[] args){
        Data data = new Data();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.print5();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"Thread01").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.print10();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"Thread02").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.print15();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"Thread03").start();
    }
}

class Data{
    private int number = 1;

    private Lock lock = new ReentrantLock();

    //实现精准访问
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();

    public void print5() throws InterruptedException {
        lock.lock();
        try {
            //判断
            while (number != 1){
                condition1.await();
            }
            //执行
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+i);
            }
            //通知
            number = 2;
            condition2.signal();//唤醒
        } finally {
            lock.unlock();
        }
    }
    public void print10() throws InterruptedException {
        lock.lock();
        try {
            //判断
            while (number != 2){
                condition2.await();
            }
            //执行
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+i);
            }
            //通知
            number = 3;
            condition3.signal();//唤醒
        } finally {
            lock.unlock();
        }
    }
    public void print15() throws InterruptedException {
        lock.lock();
        try {
            //判断
            while (number != 3){
                condition3.await();
            }
            //执行
            for (int i = 0; i < 15; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+i);
            }
            //通知
            number = 1;
            condition1.signal();//唤醒
        } finally {
            lock.unlock();
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值