JavaSE高级:JUC并发(上)

本文详细介绍了Java并发编程中的JUC(Java Util Concurrency)工具包,包括线程和进程的概念,锁的使用,如公平锁和非公平锁,以及并发集合的不安全性。重点讲解了Lock接口及其与synchronized的区别,还探讨了生产者消费者问题的解决方案,以及线程池的重要性和四种拒绝策略。此外,文章提到了并发编程中的一些经典问题,如并发修改异常,并给出了相应的解决办法,如使用CopyOnWriteArrayList和ConcurrentHashMap。
摘要由CSDN通过智能技术生成

目录

1.什么是JUC

2.线程和进程

3.Lock锁(重点)

4.生产者和消费者问题!

5.8锁现象

6.集合类不安全

1.List不安全

2.Set不安全

3.Map不安全

7.Callable(简单)

8.常用的辅助类(必会!)

1.CountDownLatch

2.CyclickBarrier

3.Semaphore

9.读写锁

10.阻塞队列与同步队列

11.线程池(重点)


 环境搭建

创建一个普通的maven项目,并确保自己设置的项目语言级别为8

 ​​

1.什么是JUC

java.util 是Java的一个工具包~ 

  • 业务:无法通过普通的线程代码 Thread实现。
  • Runnable 没有返回值、效率相比于Callable相对较低!
  • 企业开发中Callable 使用较多

2.线程和进程

进程:一个程序,QQ.EXE Music.EXE;数据+代码+pcb

  • 一个进程可以包含多个线程,至少包含一个线程!
  • Java默认有几个线程?2个线程! main线程、GC线程

线程:开了一个进程Typora,写字,等待几分钟会进行自动保存(线程负责的)

  • 对于Java而言:Thread、Runable、Callable进行开启线程的,我们之前。
  • 提问?JAVA真的可以开启线程吗? 开不了的!
public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    private native void start0();

Java是没有权限去开启线程、操作硬件的,这是一个native的一个本地方法,它调用的底层的C++代码。

并发、并行

并发:多线程操作同一个资源。

  • CPU 只有一核,模拟出来多条线程,天下武功,唯快不破。那么我们就可以使用CPU快速交替,来模拟多线程。
  • 并发编程的本质:充分利用CPU的资源!

并行: 多个人一起行走

  • CPU多核,多个线程可以同时执行。 我们可以使用线程池!
public class Test1 {
    public static void main(String[] args) {
        //获取cpu的核数
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

并发编程的本质:充分利用CPU的资源!

线程有几个状态?

线程的状态:6个状态

public enum State {
        //新生
        NEW,

        //运行
        RUNNABLE,

        //堵塞
        BLOCKED,

        //等待,一直等
        WAITING,

        //超时等待,规定时间,到了就不等了
        TIMED_WAITING,

        /终止
        TERMINATED;
    }

wait/sleep的区别?

1.来自不同的类

wait => Object

sleep => Thread

一般情况企业中使用休眠是:

        TimeUnit.DAYS.sleep(1); //休眠1天
        TimeUnit.SECONDS.sleep(1); //休眠1s

2.关于锁的释放

wait 会释放锁;

sleep睡觉了,不会释放锁;

3.使用的范围是不同的

wait 必须在同步代码块中;

sleep 可以在任何地方睡;

4.是否需要捕获异常

wait是不需要捕获异常;

sleep必须要捕获异常;

3.Lock锁(重点)

传统的Synchronized

/**
 * 真正的多线程开发
 * 线程就是一个单独的资源类,没有任何的附属操作!
 */
public class SaleTicketDemo01 {
    public static void main(String[] args) {
        //多线程操作
        //并发:多线程操作同一个资源类,把资源类丢入线程
        Ticket ticket = new Ticket();

        //@FunctionalInterface 函数式接口 jdk1.8之后 lambda表达式(参数)->{代码}
        new Thread(()->{
            for(int i=0;i<20;i++){
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
            for(int i=0;i<20;i++){
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
            for(int i=0;i<20;i++){
                ticket.sale();
            }
        },"C").start();
    }
}
//资源类
//属性+方法
//oop
class Ticket{
    private int number=20;


    //卖票的方式
    // synchronized 本质:队列,锁
    public synchronized void sale(){
        if(number>0){
            System.out.println(Thread.currentThread().getName()+" 卖出了第"+number+" 张票,剩余:"+number+" 张票");
            number--;
        }
    }
}

Lock接口

公平锁: 十分公平,必须先来后到~;比如这里有一个三秒就结束的事情,和3小时结束的事情,这时候如果先来的是3小时才能结束的需求,又来一个3秒结束的需求,这里就不能调换位置

非公平锁: 十分不公平,可以插队;(默认为非公平锁),反之这里可以先完成3秒的需求再去继续完成3小时的需求

public class SaleTicketDemo02 {
    public static void main(String[] args) {
        //多线程操作
        //并发:多线程操作同一个资源类,把资源类丢入线程
        Ticket2 ticket = new Ticket2();
        new Thread(()->{for(int i=0;i<40;i++) ticket.sale(); },"A").start();
        new Thread(()->{for(int i=0;i<40;i++) ticket.sale(); },"B").start();
        new Thread(()->{for(int i=0;i<40;i++) ticket.sale(); },"C").start();
    }
}

//lock三部曲
//1、    Lock lock=new ReentrantLock();
//2、    lock.lock() 加锁
//3、    finally=> 解锁:lock.unlock();
class Ticket2{
    private int number=50;

    Lock lock=new ReentrantLock();

    //卖票的方式
    // 使用Lock 锁
    public void sale(){
        //加锁
        lock.lock();
        try {
            //业务代码
            if(number>=0){
                System.out.println(Thread.currentThread().getName()+" 卖出了第"+number+" 张票,剩余:"+number+" 张票");
                number--;
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            //解锁
            lock.unlock();
        }
    }
}

Synchronized 和 Lock区别

  • 1.Synchronized 内置的Java关键字,Lock是一个Java类
  • 2.Synchronized 无法判断获取锁的状态,Lock可以判断
  • 3.Synchronized 会自动释放锁,lock必须要手动加锁和手动释放锁!可能会遇到死锁
  • 4.Synchronized 线程1(获得锁->阻塞)、线程2(等待);lock就不一定会一直等待下去,lock会有一个trylock去尝试获取锁,不会造成长久的等待。
  • 5.Synchronized 是可重入锁,不可以中断的,非公平的;Lock,可重入的,可以判断锁,可以自己设置公平锁和非公平锁;
  • 6.Synchronized 适合锁少量的代码同步问题;Lock适合锁大量的同步代码(灵活度更高)

锁到底是什么? 如何判断锁的是谁?

4.生产者和消费者问题!

Synchronized wait notify可以实现,该方法是传统版本;

我们这次使用lock版本

Synchronized版本

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

        new Thread(()->{for(int i=0;i<10;i++) {
            try {
                data.increment();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        },"A").start();
        new Thread(()->{for(int i=0;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()+"=>"+number);
        //通知其他线程 我+1完毕了
        this.notifyAll();
    }

    //-1
    public synchronized void decrement() throws InterruptedException {
        if(number==0){
            //等待操作
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        //通知其他线程  我-1完毕了
        this.notifyAll();
    }

}

问题存在,A线程B线程,现在如果我有四个线程A B C D!

解决方案: if 改为while即可,防止虚假唤醒

JUC版本的生产者和消费者问题

await、signal 替换 wait、notify

通过Lock找到Condition

public class B {
    public static void main(String[] args) {
        Data2 data = new Data2();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data.increment();
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data.decrement();
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data.increment();
            }
        }, "C").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data.decrement();
            }
        }, "D").start();
    }
}

class Data2 {
    //数字  资源类
    private int number = 0;

    //lock锁
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    //+1
    public void increment() {
        lock.lock();
        try {
            //业务
            while (number != 0) {
                //等待操作
                condition.await();
       
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值