首页 后端 Java 正文

高频多线程高并发JUC编程(一)

什么是JUC

高频多线程高并发JUC编程(一)  第1张

源码+官方文档

JUC是 java util concurrent

面试高频问JUC~!

高频多线程高并发JUC编程(一)  第2张

java.util 是Java的一个工具包

业务:普通的线程代码 Thread

Runnable: 没有返回值、效率相比于Callable 相对较低!

高频多线程高并发JUC编程(一)  第3张

线程和进程

进程:一个程序,允许一个java程序会进程里面会出现一个java.exe;数据+代码+pcb

一个进程可以包含多个线程,至少包含一个线程!

Java默认有几个线程?2个线程! main线程、GC线程

线程:开了一个进程qq,聊天打字,消息提示(线程负责的)

对于Java而言:Thread、Runable、Callable进行开启线程的。

JAVA真的可以开启线程吗? 开不了的! 原因Java没有权限去开启线程、操作硬件的,这是一个native的一个本地方法,它调用的底层的C++代码。

并发、并行

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

  • CPU 只有一核,模拟出来多条线程,那么我们就可以使用CPU快速交替,来模拟多线程。

并行: 多个人并排行走。

  • CPU多核,多个线程可以同时执行。

public class Test {
    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区别?

区别waitsleep
操作的类ObjectThread
锁的释放会释放锁抱着锁睡觉
范围同步代码块中任何地方
异常捕获不需要捕获异常需要捕获异常

Lock锁(重点)

synchronized锁问题

package com.zmz.day01;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.day01
 * @ClassName: TicketTest
 * @Author: 张晟睿
 * @Date: 2021/9/5 14:01
 * @Version: 1.0
 */
//资源类 属性 + 方法 oop
class Ticket{
    private int num = 50;
    //卖票方式  synchronized 本质:队列 锁
    public synchronized void sale(){
        if(num > 0){
            System.out.println(Thread.currentThread().getName()+ " 卖出了第"+ num +" 张票,剩余:"+ --num +" 张票");
        }
    }
}


public class TicketTest {
    public static void main(String[] args) {
        //多线陈操作
        //并发:多个线程操作同一个资源ticket
        Ticket ticket = new Ticket();
        //@FunctionalInterface 函数式接口 jdk1.8之后 lambda表达式
        new Thread(()->{
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        },"C").start();
    }
}


Lock接口

高频多线程高并发JUC编程(一)  第4张

高频多线程高并发JUC编程(一)  第5张

高频多线程高并发JUC编程(一)  第6张

公平锁: 公平,必须先来后到~;

非公平锁: 不公平,可以插队;(默认为非公平锁)

使用Lock进行操作

  • Lock实现提供比使用synchronized方法和语句可以获得的更广泛的锁定操作。 它们允许更灵活的结构化,可能具有完全不同的属性,并且可以支持多个相关联的对象Condition

  • 锁是用于通过多个线程控制对共享资源的访问的工具。 通常,锁提供对共享资源的独占访问:一次只能有一个线程可以获取锁,并且对共享资源的所有访问都要求首先获取锁。 但是,一些锁可能允许并发访问共享资源,如ReadWriteLock的读锁。

  • 使用synchronized方法或语句提供对与每个对象相关联的隐式监视器锁的访问,但是强制所有锁获取和释放以块结构的方式发生:当获取多个锁时,它们必须以相反的顺序被释放,并且所有的锁都必须被释放在与它们相同的词汇范围内。

  • 虽然synchronized方法和语句的范围机制使得使用监视器锁更容易编程,并且有助于避免涉及锁的许多常见编程错误,但是有时您需要以更灵活的方式处理锁。 例如,用于遍历并发访问的数据结构的一些算法需要使用“手动”或“链锁定”:您获取节点A的锁定,然后获取节点B,然后释放A并获取C,然后释放B并获得D等。 所述的实施方式中Lock接口通过允许获得并在不同的范围释放的锁,并允许获得并以任何顺序释放多个锁使得能够使用这样的技术。

  • 随着这种增加的灵活性,额外的责任。 没有块结构化锁定会删除使用synchronized方法和语句发生的锁的自动释放。 在大多数情况下,应使用以下惯用语:

       Lock l = ...; l.lock(); 
       try { 
       // access the resource protected by this lock 
       } finally {
           l.unlock(); 
       }
  • 当在不同范围内发生锁定和解锁时,必须注意确保在锁定时执行的所有代码由try-finally或try-catch保护,以确保在必要时释放锁定。

  • Lock实现提供了使用synchronized方法和语句的附加功能,通过提供非阻塞尝试来获取锁( tryLock() ),尝试获取可被中断的锁( lockInterruptibly()) ,以及尝试获取可以超时( tryLock(long, TimeUnit) )。

  • 一个Lock类还可以提供与隐式监视锁定的行为和语义完全不同的行为和语义,例如保证排序,非重入使用或死锁检测。 如果一个实现提供了这样的专门的语义,那么实现必须记录这些语义。

  • 请注意, Lock实例只是普通对象,它们本身可以用作synchronized语句中的目标。 获取Lock实例的监视器锁与调用该实例的任何lock()方法没有特定关系。 建议为避免混淆,您不要以这种方式使用Lock实例,除了在自己的实现中。

    除非另有说明,传递任何参数的null值将导致NullPointerException被抛出。

    内存同步

    所有Lock实施必须执行与内置监视器锁相同的内存同步语义,如The Java Language Specification (17.4 Memory Model) 所述

    不成功的锁定和解锁操作以及重入锁定/解锁操作,不需要任何内存同步效果。

    • 成功的lock操作具有与成功锁定动作相同的内存同步效果。

    • 成功的unlock操作具有与成功解锁动作相同的内存同步效果。

实施注意事项

  • 锁定采集(可中断,不可中断和定时)的三种形式在性能特征,排序保证或其他实施质量方面可能不同。 此外,在给定的Lock课程中,中断正在获取锁的能力可能不可用。 因此,不需要实现对所有三种形式的锁获取完全相同的保证或语义,也不需要支持正在进行的锁获取的中断。 需要一个实现来清楚地记录每个锁定方法提供的语义和保证。 它还必须遵守此接口中定义的中断语义,只要支持锁获取的中断,即全部或仅在方法输入。

  • 由于中断通常意味着取消,并且检查中断通常是不频繁的,所以实现可以有利于通过正常方法返回来响应中断。 即使可以显示中断发生在另一个动作可能已经解除了线程之后,这是真的。 一个实现应该记录这个行为。

package com.zmz.day01;/**
 * @ProjectName: Juc
 * @Package: com.zmz.day01
 * @ClassName: TicketTest2
 * @Author: 张晟睿
 * @Date: 2021/9/5 16:15
 * @Version: 1.0
 */

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

/**
 *@ClassName TicketTest2
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/5
 **/

class Ticket2{
    /*
    * 加锁三步
    * 1.实例化lock对象
    * 2.lock加锁
    * 3.unlock解锁
    * */
    Lock l = new ReentrantLock();
    private int num = 50;
    //卖票方式  synchronized 本质:队列 锁
    public  void sale(){
        //加锁
        l.lock();
        try {
            //业务代码
            if(num > 0){
                System.out.println(Thread.currentThread().getName()+ " 卖出了第"+ num +" 张票,剩余:"+ --num +" 张票");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //解锁
            l.unlock();
        }
    }
}


public class TicketTest2 {
    public static void main(String[] args) {
        //多线陈操作
        //并发:多个线程操作同一个资源ticket
        Ticket ticket = new Ticket();
        //@FunctionalInterface 函数式接口 jdk1.8之后 lambda表达式
        new Thread(()->{
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        },"C").start();
    }
}
区别synchronizedlock
名称属于关键字属于对象
状态不可以获取锁的状态可以获取锁的状态
锁的管理自动释放锁需要手动加锁以及释放锁
线程自己抱着锁等待

可重入锁,不可以中断的,非公平的可重入的,可以判断锁,可以自己设置公平锁和非公平锁
代码同步适合少量的代码同步适合大量的代码同步

生产者消费者问题

synchronized版

package com.zmz.day01;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.day01
 * @ClassName: TicketTest3
 * @Author: 张晟睿
 * @Date: 2021/9/5 16:35
 * @Version: 1.0
 */

/**
 *@ClassName TicketTest3
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/5
 **/
public class TicketTest3 {
    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);
        this.notifyAll();
    }
    //      -1操作
    public synchronized void decrement() throws InterruptedException{
        if (number == 0){
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notifyAll();
    }
}

问题存在,A线程B线程,现在如果我有四个线程A B C D!该怎么去解决问题

高频多线程高并发JUC编程(一)  第7张

if判断改为While判断就可以解决虚假唤醒的问题。

package com.zmz.day01;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.day01
 * @ClassName: TicketTest3
 * @Author: 张晟睿
 * @Date: 2021/9/5 16:35
 * @Version: 1.0
 */

/**
 *@ClassName TicketTest3
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/5
 **/
//线程之间的通讯问题:生产者和消费者的问题!  等待唤醒,通知唤醒
//线程交替执行 A   B操作同一个资源
public class TicketTest3 {
    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();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; 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()+"=>"+number);
        this.notifyAll();
    }
    //      -1操作
    public synchronized void decrement() throws InterruptedException{
        while (number == 0){
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notifyAll();
    }
}

JUC版本的解决A B  C D多线程的问题

高频多线程高并发JUC编程(一)  第8张

package com.zmz.day01;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.day01
 * @ClassName: JucTest1
 * @Author: 张晟睿
 * @Date: 2021/9/5 19:34
 * @Version: 1.0
 */

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

/**
 *@ClassName JucTest1
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/5
 **/
public class JucTest1 {
    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 l = new ReentrantLock();
    Condition condition = l.newCondition();

    public void increment() {
        l.lock();
        try {
            //业务
            while (number!=0){
                //等待操作
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName()+"=>"+number);
            //通知其他线程 我+1完毕了
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            l.unlock();
        }
    }

    public void decrement()  {
        l.lock();
        try {
            //业务
            while (number==0){
                //等待操作
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName()+"=>"+number);
            //通知其他线程 我-1完毕了
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            l.unlock();
        }
    }
}

Condition的优势:精准通知、唤醒的线程

package com.zmz.day01;
/**
 * @ProjectName: Juc
 * @Package: com.zmz.day01
 * @ClassName: JucTest2
 * @Author: 张晟睿
 * @Date: 2021/9/5 19:52
 * @Version: 1.0
 */

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

/**
 *@ClassName JucTest2
 *@Description
 *@Author 张晟睿
 *@Date 2021/9/5
 **/
public class JucTest2 {
    public static void main(String[] args) {
        Data3 data3 = new Data3();
        new Thread(()->{
            for(int i=0;i<10;i++){
                data3.printA();
            }
        },"A").start();
        new Thread(()->{
            for(int i=0;i<10;i++){
                data3.printB();
            }
        },"B").start();
        new Thread(()->{
            for(int i=0;i<10;i++){
                data3.printC();
            }
        },"C").start();
    }
}


class Data3{
    private Lock l = new ReentrantLock();
    Condition condition1 = l.newCondition();
    Condition condition2 = l.newCondition();
    Condition condition3 = l.newCondition();

    private int flag = 1;
    public void printA(){
        l.lock();
        //判断 -> 执行 -> 通知
        try {
            while(flag != 1){
                //等待
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName() + "->A" );
            flag = 2;
            //唤醒指定线程
            condition2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            l.unlock();
        }
    }

    public void printB(){
        l.lock();
        //判断 -> 执行 -> 通知
        try {
            while(flag != 2){
                //等待
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName() + "->BB" );
            flag = 3;
            //唤醒指定线程
            condition3.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            l.unlock();
        }
    }

    public void printC(){
        l.lock();
        //判断 -> 执行 -> 通知
        try {
            while(flag != 3){
                //等待
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName() + "->CCC" );
            flag = 1;
            //唤醒指定线程
            condition1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            l.unlock();
        }
    }
}

作者:Java厂长

打赏
海报

本文转载自互联网,旨在分享有价值的内容,文章如有侵权请联系删除,部分文章如未署名作者来源请联系我们及时备注,感谢您的支持。

转载请注明本文地址:https://www.shouxicto.com/article/2677.html

相关推荐

发布评论

ainiaobaibaibaibaobaobeishangbishibizuichiguachijingchongjingdahaqiandaliandangaodw_dogedw_erhadw_miaodw_tuzidw_xiongmaodw_zhutouganbeigeiliguiguolaiguzhanghahahahashoushihaixiuhanheixianhenghorse2huaixiaohuatonghuaxinhufenjiayoujiyankeaikeliankouzhaokukuloukunkuxiaolandelinileimuliwulxhainiolxhlikelxhqiuguanzhulxhtouxiaolxhwahahalxhzanningwennonuokpinganqianqiaoqinqinquantouruoshayanshengbingshiwangshuaishuijiaosikaostar0star2star3taikaixintanshoutianpingtouxiaotuwabiweifengweiquweiwuweixiaowenhaowoshouwuxiangjixianhuaxiaoerbuyuxiaokuxiaoxinxinxinxinsuixixixuyeyinxianyinyueyouhenghengyuebingyueliangyunzanzhajizhongguozanzhoumazhuakuangzuohenghengzuoyi
支付宝
微信
赞助本站