01_JUC概述

news2024/11/29 4:42:00

1. JUC是什么?

在 Java 5.0 提供了 java.util.concurrent(简称JUC)包,在此包中增加了在并发编程中很常用的工具类。此包包括了几个小的、已标准化的可扩展框架,并提供一些功能实用的类,没有这些类,一些功能会很难实现或实现起来冗长乏味。

参照JDK文档:

2. 进程和线程

进程:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。

线程:通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统多个程序间并发执行的程度。

线程多了好还是少好?

合理最好: 一般和CPU核心数差不错最好
1、如果程序执行的是耗时操作 线程多一些好
2、如果程序执行的是cpu计算型操作,线程越少越好   cpu调度线程时 切换上下文也需要时间

生活实例: 

  • ​使用QQ,查看进程一定有一个QQ.exe的进程,我可以用qq和A文字聊天,和B视频聊天,给C传文件,给D发一段语言,QQ支持录入信息的搜索。
  • ​大四的时候写论文,用word写论文,同时用QQ音乐放音乐,同时用QQ聊天,多个进程。
  • word如没有保存,停电关机,再通电后打开word可以恢复之前未保存的文档,word也会检查你的拼写,两个线程:容灾备份,语法检查

3. 并行和并发

串行:

资源:服务器中的一个文件 或者是某个接口

并发:同一时刻多个线程在访问同一个资源,多个线程对一个点

​例子:小米13pro今天上午10点,限量抢购

春运抢票

电商秒杀...

并行:多项工作一起执行,之后再汇总

例子:泡方便面,电水壶烧水,一边撕调料倒入桶中

4. wait/sleep的区别

功能都是当前线程暂停,有什么区别?

wait:放开手去睡,放开手里的锁

sleep:握紧手去睡,醒了手里还有锁

wait是Object的方法,sleep是thread的方法

wait从等待时所在的行继续向后执行

5. 创建线程回顾

创建线程常用两种方式:

  • 继承Thread:java是单继承,资源宝贵,要用接口方式
  • 实现Runnable接口

5.1 继承Thread抽象类

public class MyThread extends Thread
new MyThread().start();

5.2 实现Runnable接口的方式

① 新建类实现runnable接口。这种方法会新增类,有更好的方法

class MyRunnable implements Runnable//新建类实现runnable接口
new Thread(new MyRunnable(), name).start() // 使用Rannable实现类创建进程,name是线程名

② 匿名内部类

new Thread(new Runnable() {
    @Override
    public void run() {
 		// 调用资源方法,完成业务逻辑
    }
}, "your thread name").start();

6. lambda表达式

之前说了Runnable接口的两种实现方式,其实还有第三种:

1. 创建类实现Runnable接口
2. 编写匿名内部类实现Runnable接口
3. lambda表达式:这种方法代码更简洁精炼

new Thread(() -> {

}, "your thread name").start();

6.1 什么是lambda

Lambda 是一个匿名函数,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或剪头操作符。它将 Lambda 分为两个部分:

  • 左侧:指定了 Lambda 表达式需要的所有参数
  • 右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能

6.2案例

在一个方法中调用接口中的方法:传统写法

interface Foo {

    public int add(int x, int y);
}

public class LambdaDemo {
    public static void main(String[] args) {
        Foo foo = new Foo() {
            @Override
            public int add(int x, int y) {
                return x + y;
            }
        };
        System.out.println(foo.add(10, 20));
    }
}

接下来,要用lambda表达式改造。其实是改造main方法

public static void main(String[] args) {

    Foo foo = (int x, int y)->{
        return x + y;
    };
    System.out.println(foo.add(10, 20));
}

改造口诀:拷贝小括号(),写死右箭头->,落地大括号{...}

思考:如果Foo接口有多个方法,还能使用lambda表达式吗?

6.4 函数式接口

lambda表达式,必须是函数式接口,必须只有一个方法,如果接口只有一个方法java默认它为函数式接口。为了正确使用Lambda表达式,需要给接口加个注解:@FunctionalInterface。如有两个方法,立刻报错。

Runnable接口为什么可以用lambda表达式?

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

发现Runnable接口上有一个注解:@FunctionalInterface

并且该接口只有一个方法:run()方法

其实,函数式接口必须只有一个方法,这个描述并不准确,它还允许有default方法和静态方法。

例如,在Foo接口中,又添加了sub方法和mul方法:

interface Foo {

    public int add(int x, int y); // 抽象方法

    default int sub(int x, int y){ // default方法
        return x - y;
    }
    public static int mul(int x, int y){ // 静态方法
        return x * y;
    }
}

public class LambdaDemo {

    public static void main(String[] args) {

        Foo foo = (int x, int y)->{  // lambda表达式实现抽象方法
            return x + y;
        };
        System.out.println(foo.add(10, 20)); // 调用抽象方法
        System.out.println(foo.sub(30, 15)); // 调用default方法
        System.out.println(Foo.mul(10, 50)); // 通过Foo调用静态方法
    }
}

6.4 小结

lambda表达式实现接口的前提是:有且只有一个抽象方法,可以选择@FunctionalInterface注解增强函数式接口定义


改造口诀​:拷贝小括号(形参列表),写死右箭头 ->,落地大括号 {方法实现}

7. synchronized回顾

(1)多线程编程模板上

1. 线程 操作 资源类
2. 高内聚低耦合

(2)实现步骤

1. 创建资源类
2. 资源类里创建同步方法、同步代码块
3. 多线程调用

(4)例子:卖票程序

class Ticket {

    private Integer number = 20;

    public synchronized void sale(){
        if (number <= 0) {
            System.out.println("票已售罄!!!");
            return;
        }
        try {
            System.out.println(Thread.currentThread().getName() + "开始买票,当前票数:" + number);
            Thread.sleep(200);
            System.out.println(Thread.currentThread().getName() + "买票结束,剩余票数:" + --number);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

// 在main方法中创建多线程方法,测试卖票业务
public class SaleTicket {

    public static void main(String[] args) {

        Ticket ticket = new Ticket();

        new Thread(() -> {
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        }, "AAA").start();

        new Thread(() -> {
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        }, "BBB").start();

        new Thread(() -> {
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        }, "CCC").start();

    }
}

8. synchronized的8锁问题

看下面这段儿代码,回答后面的8个问题:

class Phone {

    public synchronized void sendSMS() throws Exception {
        //TimeUnit.SECONDS.sleep(4);
        System.out.println("------sendSMS");
    }

    public synchronized void sendEmail() throws Exception {
        System.out.println("------sendEmail");
    }

    public void getHello() {
        System.out.println("------getHello");
    }

}

public class Lock_8 {

    public static void main(String[] args) throws Exception {

        Phone phone = new Phone();
        Phone phone2 = new Phone();

        new Thread(() -> {
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "AA").start();

        Thread.sleep(100);

        new Thread(() -> {
            try {
                phone.sendEmail();
                //phone.getHello();
                //phone2.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "BB").start();
    }
}

多线程的8个问题:

1. 标准访问,先打印短信还是邮件
2. 停4秒在短信方法内,先打印短信还是邮件
3. 普通的hello方法,是先打短信还是hello
4. 现在有两部手机,先打印短信还是邮件
5. 两个静态同步方法,1部手机,先打印短信还是邮件
6. 两个静态同步方法,2部手机,先打印短信还是邮件
7. 1个静态同步方法,1个普通同步方法,1部手机,先打印短信还是邮件
8. 1个静态同步方法,1个普通同步方法,2部手机,先打印短信还是邮件

答案:

1. 标准访问,先打印短信还是邮件: 先短信
2. 停4秒在短信方法内,先打印短信还是邮件:先短信(两个方法锁的对象都是调用方法的phone)
3. 普通的hello方法,是先打短信还是hello:先hello(hello方法未加锁)
4. 现在有两部手机,先打印短信还是邮件:先邮件(两个线程各自用各自的锁)
5. 两个静态同步方法,1部手机,先打印短信还是邮件:先短信
6. 两个静态同步方法,2部手机,先打印短信还是邮件:先短信(静态方法调用锁定的对象和谁调用无关,锁的一定是类对象)
7. 1个静态同步方法,1个普通同步方法,1部手机,先打印短信还是邮件:先邮件
8. 1个静态同步方法,1个普通同步方法,2部手机,先打印短信还是邮件:先邮件
一个线程会等待另一个线程释放锁以后执行,那么它俩争抢的锁一定是同一个 

总结:

synchronized实现同步的基础:Java中的每一个对象都可以作为锁。具体表现为以下3种形式:

1. 对于普通同步方法,锁是当前实例对象。
2. 对于静态同步方法,锁是当前类的Class对象。
3. 对于同步方法块,锁是Synchonized括号里配置的对象

当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。

也就是说:

  • 如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁;可是不同实例对象的非静态同步方法因为用的是不同对象的锁,所以毋须等待其他实例对象的非静态同步方法释放锁,就可以获取自己的锁。
  • 所有的静态同步方法用的是同一把锁——类对象本身。不管是不是同一个实例对象,只要是一个类的对象,一旦一个静态同步方法获取锁之后,其他对象的静态同步方法,都必须等待该方法释放锁之后,才能获取锁。
  • 而静态同步方法(Class对象锁)与非静态同步方法(实例对象锁)之间是不会有竞态条件的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/474143.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

玩手机打电话识别监测算法 yolov8

玩手机打电话识别监测系统通过YOLOv8网络模型技术&#xff0c;玩手机打电话识别监测算法对现场有人玩手机抽烟打电话时可以立即自动进行抓拍存档。YOLOv8 算法的核心特性和改动可以归结为如下&#xff1a;提供了一个全新的 SOTA 模型&#xff0c;包括 P5 640 和 P6 1280 分辨率…

【全年汇总】2023年CCF人工智能会议截稿时间汇总(持续更新)

本博文是根据2022年CCF会议推荐的人工智能领域相关会议目录撰写。 一、截稿时间总览 截稿时间的总时间轴内容将会持续更新...... 往年投稿及录用情况及链接详见图片后面的内容。 二、会议详细目录 由于一些会议的投稿时间还没公开&#xff0c;因此根据往年投稿时间在表格中使…

石化企业数字化防爆融合通信解决方案

项目背景 石化工业是我国国民经济和社会发展的基础性、战略性产业&#xff0c;其发展和壮大受到了党和国家的高度重视。随着石化企业厂区规模的不断扩大以及技术的快速发展&#xff0c;现有石化企业专网通信系统建设相对滞后&#xff0c;缺乏结合人员管理、安全生产、安全通信…

商品详情API接口如何获取淘宝数据

淘宝是中国最大最受欢迎的电商平台之一&#xff0c;汇集了大量的商家和买家。在淘宝上热门商品的销量经常十分巨大&#xff0c;因此有些开发者和网站想要获取淘宝商品数据来进行一些分析。下面是一篇关于淘宝商品详情API接口获取淘宝数据的文章。 一、淘宝商品API接口介绍 淘…

HadaFS - Burst Buffer解读

背景 近几年AI&#xff0c;ML&#xff0c;HPC大火&#xff0c; 针对这些场景的存储技术及方案也逐步衍生出两个分支&#xff0c;第一支&#xff1a;以Lustre&#xff0c;BeeGFS等为代表的分布式并行文件系统&#xff0c; 这些文件系统对POSIX提供了很好的支持&#xff0c;各种…

Idea关闭或开启引用提示Usages和Annotations

IDEA的引用提示与Annotation 在2022版本的Idea中&#xff0c;新增了引用提示&#xff08;Usages&#xff09;和作者&#xff08;Annotations&#xff09;的功能。虽然用起来挺好用的&#xff0c;但对电脑还是有一定的压力&#xff0c;在配置比较低的电脑上&#xff0c;打开一个…

PHP入门【1】使用组合包安装php

目录 一&#xff0c;安装appserv组合包 二&#xff0c;运行第一个php程序 一&#xff0c;安装appserv组合包 组合包&#xff1a;将apache&#xff0c;mysql&#xff0c;php等服务器软件和工具安装配置完成后打包处理 组合包大大提高了我们的效率&#xff0c;不需要为配置环境…

使用Python和机器学习进行文本情感分类

使用Python和机器学习进行文本情感分类 1. 效果图2. 原理3. 源码参考这篇博客将介绍如何使用Python进行机器学习的文本情感分类(Text Emotions Classification)。 1. 效果图 训练文本及情感分类前5条数据如下: 训练过程及测试文本情感分类效果图如下: 可以看到 对文本“S…

javaEE初阶 — 服务器版本的表白墙案例

文章目录 原来版本涉及的问题设计程序1 点击提交2 页面加载 实现后端代码1 新建一个 Maven 项目。2 按照之前第一个 Servlet 程序的步骤来进行设置3 新建一个 MessageServlet 类 实现前端代码1 点击提交的时给服务器发送一个 POST 请求2 在页面加载时发送一个 GET 请求3 将数据…

如何学习数据结构和算法

背景&#xff1a; 对待数据结构与算法的态度可能大多数人就是觉得晦涩难懂。这节课我们跟随老师看看老师是如何带领我们入门的。 定义&#xff1a; 首先我们了解数据结构和算法的定义&#xff1a; 从广义上讲&#xff0c;数据结构就是指一组数据的存储结构。算法就是操作数…

MES系统8路热电偶温度输出太网口

8路热电偶温度模块可以同时采集8个热电偶信号&#xff0c;并且具备高精度、高稳定性和良好的抗干扰性能&#xff0c;非常适合工业领域中需要监测多个物体温度的应用场景。 该热电偶温度模块拥有以下几个特点&#xff1a; 1. 8个差分输入通道&#xff0c;支持多种类型的热电偶…

【排序】归并排序(递归+非递归图示详解哦)

全文目录 引言归并排序思路递归实现 归排非递归思路实现 总结 引言 在本篇文章中&#xff0c;将继续介绍一种排序算法&#xff1a;归并排序。 归并排序运用了归并的思想&#xff0c;即将两个有序数列归并为一个有序数列。在前面的合并两个有序链表时&#xff0c;运用了这种思想…

四福来轮全向底盘实现写字功能

1. 功能说明 本文示例将实现R310b样机四福来轮全向底盘绘制“探索者”空心字的功能。 2. 电子硬件 本实验中采用了以下硬件&#xff1a; 主控板 Basra主控板&#xff08;兼容Arduino Uno&#xff09; 扩展板 Bigfish2.1扩展板 SH-ST步进电机扩展板电池11.1v动力电池 其它 步进…

干货分享:AI绘图学习心得-Midjourney绘画AI,让你的AI绘画之路少走弯路

干货分享&#xff1a;AI绘图学习心得-Midjourney绘画AI 最重要的Prompt和参数基本 Prompts高级Prompts 一、构图指令结构二、常用指令分享三、操作技巧总结四、常用风格词汇五、常用构图词汇六、高频实用词汇推荐&#xff1a;七、其他AI资料获取&#xff1a; 本篇没有什么长篇大…

01-Vue技术栈之基础篇(上)

目录 1、Vue简介1.1 Vue官网1.2 介绍与描述1.3 Vue 的特点1.4 与其它 JS 框架的关联1.5 Vue 周边库 2. 初识Vue2.1 Vue初体验2.2 注意事项2.3 js表达式和js代码&#xff08;语句&#xff09; 3、Vue模板语法3.1 语法分类3.2 插值语法3.3 指令语法 4、Vue模板语法4.1 数据绑定方…

Java中几种常量池面试总结

字符串常量池&#xff08;string pool&#xff09; 字符串常量池是JVM为了提升性能和减少内存消耗针对字符串&#xff08;String类&#xff09;专门开辟的一块区域&#xff0c;主要目的是为了避免字符串的重复创建。 当需要使用字符串时&#xff0c;先去字符串池中查看该字符…

使用vscode 创建vue3.0项目,应用element-plus框架

使用npm指令创建项目 npm init vite-app 项目名称 npm install npm run dev输入http://localhost:3000/ 查看 2、可自定义vue模板 输入vue.json 回车。复制下述代码&#xff0c;然后保存。 {"Print to console": {"prefix": "vue","b…

每天一道算法练习题--Day15 第一章 --算法专题 --- -----------二叉树的遍历

概述 二叉树作为一个基础的数据结构&#xff0c;遍历算法作为一个基础的算法&#xff0c;两者结合当然是经典的组合了。很多题目都会有 ta 的身影&#xff0c;有直接问二叉树的遍历的&#xff0c;有间接问的。比如要你找到树中满足条件的节点&#xff0c;就是间接考察树的遍历…

STM32物联网实战开发(3)——串口打印

串口打印 串口的使用在单片机开发过程中经常出现&#xff0c;因为他在显示数据和调试过程中特别的方便&#xff0c;使用起来也很简单。 1.用STM32CubeMx配置串口 串口1模式选择异步&#xff0c;不开启硬件控制流&#xff08;串口通信分为同步通信和异步通信&#xff0c;他们往…

云HIS : 电子病历模板制作过程技术经验分享

电子病历的制作就是按照医院机构的特色&#xff0c;根据不同业务需求&#xff0c;使用模板编辑与预览工具&#xff0c; 综合运用工具模块制作个性化、实用化、特色化电子病历模板的过程。 按照制作流程分为以下几个步骤&#xff1a; 1.明确病历类型&#xff1a;根据业务方向…