1502 - JUC高并发

news2024/11/14 19:19:26

慢慢挣,今天比昨天更有钱,明天比今天有钱,后天比明天有钱。

0.思维导图

6.多线程锁

synchronized实现同步的基础:Java中的每一个对象都可以作为锁

具体表现为以下3中形式

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

6.1 synchronized 锁的八种情况总结

视频案例

class Phone {
    // 模拟发送短信操作
    public synchronized void sendSMS() throws InterruptedException {
        // 停留3秒在短信内
        TimeUnit.SECONDS.sleep(3);
        System.out.println("------sendSMS------");
    }

    // 模拟发送邮件操作
    public synchronized void sendEmail() {
        System.out.println("------sendEmail------");
    }

    // 普通方法 打招呼
    public void sayHello() {
        System.out.println("------sayHello------");
    }

}


public class ThreadDemo {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone1 = new Phone();
        // 创建一个线程,调用Phone的sendSMS()方法
        new Thread(() -> {
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
        // 创建一个线程,调用Phone的sendEmail()方法
        new Thread(() -> {
            try {
//                phone.sayHello();
//                phone.sendEmail();
                phone1.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        ).start();
    }
}

不同案例输出的结果分析

  • 1.标准访问,先打印短信还是邮件

输出结果

------sendSMS------
------sendEmail------

原因分析

按线程启动顺序获取锁释放锁。

  • 2.停3秒在短信方法内,先打印短信还是邮件

输出结果

------sendSMS------
------sendEmail------

原因分析

此时获取同一个对象锁,第一次获取锁后等待3秒,执行完释放锁之后,第二个线程才能获取同一把对象锁。

  • 3.新增普通的hello方法,在线程2中调用,是先发短信还是hello

输出结果

------sayHello------
------sendSMS------
------sendEmail------

原因分析

线程A获取到锁,开始等待,因为线程B执行不许要获取同步锁,所以先输出sayHello,然后经过3秒,线程A等待结束,执行输出操作并释放锁。

  • 4.现在有两部手机,先打印短信还是邮件

输出结果

------sendEmail------
------sendSMS------

原因分析

线程A和B获取到不同的对象锁,之间没有竞争关系,因此B线程先输出,A先等待结束之后输出。

  • 5.两个静态同步方法,一部手机,先打印短信还是邮件

输出结果

------sendSMS------
------sendEmail------

原因分析

静态方法,是Class锁,线程A和B争夺同一把类锁,线程A 先获取锁,因此A等待3秒执行输出释放锁之后,B才获取到锁并执行输出。

  • 6.两个静态同步方法,两部手机,先打印短信还是邮件

输出结果

------sendSMS------
------sendEmail------

原因分析

线程A和B通过不同对象争夺同一把类锁,线程A 先获取锁,因此A等待3秒执行输出释放锁之后,B才获取到锁并执行输出。

  • 7.一个静态同步方法,一个普通同步方法,一部手机,先打印短信还是邮件

输出结果

------sendEmail------
------sendSMS------

原因分析

线程A获取类锁,执行等待,期间线程B获取对象锁,执行输出并释放对象锁,线程A等待结束执行输出释放类锁。(因为获取的锁对象不同,不存在竞争,按照时间顺序输出)

  • 8.一个静态同步方法,一个普通同步方法,两部手机,先打印短信还是邮件

输出结果

------sendEmail------
------sendSMS------

原因分析

通过不同对象获取不同的锁,不存在竞争。

6.2 公平锁和非公平锁

  • 公平锁 :效率相对低 ,阳光普照,每一个线程都参与工作。
  • 非公平锁:效率高,但是线程容易饿死,所有的工作,都由一个线程完成。

用法:在创建可重入锁ReentrantLock时,调用有参构造器,传入参数true设置为公平锁。

private final ReentrantLock lock = new ReentrantLock(true);

jdk源码

两者性能差距 

公平锁询问,如果有人,则进行排队等待

6.3 可重入锁

可重入锁就是某个线程已经获得某个锁,可以重复获取同一个锁而不死锁,可重入锁也叫递归锁。

synchronized示例代码

public class ThreadDemo {
    // 创建一个锁对象
    static final Object myLock = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (myLock) {
                System.out.println("这是第一层锁");
                synchronized (myLock) {
                    System.out.println("这是第二层锁");
                }
            }
        }).start();
    }
}

输出结果

ReentrantLock示例代码

public class ThreadDemo {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        new Thread(() -> {
            lock.lock();
            try {
                System.out.println("这是第一层锁");
                lock.lock();
                try {
                    System.out.println("这是第二层锁");
                } finally {
                    lock.unlock();
                }
            } finally {
                lock.unlock();
            }
        }).start();
    }
}

6.4 死锁

两个或以上的进程因为争夺资源而造成互相等待资源的现象称为死锁。如果没有外力干涉,他们无法继续执行。

产生死锁的原因

  • 系统资源不足
  • 进行运行推进顺序不合理
  • 资源分配不当

死锁产生的四个必要条件

  • 互斥使用:当资源被一个线程使用或者占用时,别的线程不能使用该资源。
  • 不可抢占:获取资源的一方,不能从正在使用资源的一方抢占掠夺资源,资源只能被使用者主动释放。
  • 请求保持:资源请求者在请求别的资源时,同时保持对已有资源的占有。
  • 循环等待:即p1占有p2的资源,p2占有p3的资源,p3占有p1的资源,这样形成了一个等待环路。

死锁示例代码

public class ThreadDemo {
    static Object a = new Object();
    static Object b = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (a) {
                System.out.println("外层,已经获取a,试图获取b");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (b) {
                    System.out.println("内层");
                }
            }
        }, "A").start();

        new Thread(() -> {
            synchronized (b) {
                System.out.println("外层,已经获取b,试图获取a");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (a) {
                    System.out.println("内层");
                }
            }
        }, "B").start();
    }
}

7.Callable接口

7.1 Runnable接口与Callable接口

使用 Runnable 创建的线程缺少的一项功能,当线程终止时(即 run()完成时),我们无法使线程返回结果。为了支持此功能,Java 中提供了 Callable 接口,即线程终止(call()执行完成时)后返回结果。

对比Runnable接口Callable 接口
返回值没有
抛出异常没有
实现方法名称run()call()

7.2 Callable接口使用

代码示例

因为Thread的构造函数中没有Callable接口的参数设置,不可以直接替换,只能用FutureTask类来实现线程创建(FutureTask类既能传入Callable构造,又是Runnable接口的实现类)

class MyThread implements Callable {
    @Override
    public Integer call() throws Exception {
        return 10086;
    }
}

public class ThreadDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask futureTask = new FutureTask<>(new MyThread());

        //创建一个线程
        new Thread(futureTask,"AA").start();

        //调用FutureTask的get方法获取线程运行结果
        System.out.println(futureTask.get());
        System.out.println(Thread.currentThread().getName() + " is over");
    }
}

8.JUC强大辅助类

8.1 减少计数CountDownLatch

CountDownLatch 方法使用说明

CountDownLatch(int count);      //构造方法,创建一个值为count 的计数器。
await();      //阻塞当前线程,将当前线程加入阻塞队列。
countDown();      //对计数器进行递减1操作,当计数器递减至0时,当前线程会去唤醒阻塞队列里的所有线程。

案例
6个同学陆续离开教室之后,班长才能锁门。
如果不加 CountDownLatch类,会出现线程混乱执行,同学还未离开教室班长就已经锁门了。

不使用CountDownLatch,导致线程混乱

public class ThreadDemo {
    public static void main(String[] args) {
        for (int i = 0; i < 6; i++) {
            new Thread(() -> System.out.println(Thread.currentThread().getName() + "同学离开教室"), String.valueOf(i)).start();
        }
        System.out.println(Thread.currentThread().getName() + "班长锁门");
    }
}

运行结果

 通过CountDownLatch计数,保证主线程输出语句最后执行

public class CountDownLatchDemo {
     public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(6);
        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "同学离开教室");
                countDownLatch.countDown();
            }, String.valueOf(i)).start();
        }
        countDownLatch.await();
        System.out.println(Thread.currentThread().getName() + "班长锁门");
    }
}

运行结果

8.2 循环栅栏CyclicBarrier

CyclicBarrier 方法使用说明

CyclicBarrier(int parties,Runnable barrierAction);      //构造方法,创建一个值为parties的屏障。
await();      //当一个线程到了栅栏这里了,那么就将计数器减 1

代码示例

public class CyclicBarrierDemo {
    public static final int NUMBER = 7;

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, () -> System.out.println("集齐七颗龙珠就可以召唤神龙"));
        for (int i = 0; i < 7; i++) {
            new Thread(() -> {
                try {
                    System.out.println("第 " + Thread.currentThread().getName() + " 颗龙珠被收集到");
                    //等待
                    cyclicBarrier.await();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }, String.valueOf(i)).start();
        }
    }
}

运行结果

8.3 信号灯Semaphore

Semaphore 方法使用说明

Semaphore(int permits);      //创建具有给定的许可数和非公平的公平设置的Semapore
acquire();      //从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断
release();      //释放一个许可,将其返回给信号量

【具体案例】
6辆汽车,停3个车位

代码示例

public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);
        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "车抢到车位");
                    TimeUnit.SECONDS.sleep(new Random().nextInt(5));
                    System.out.println("--" + Thread.currentThread().getName() + "车离开车位");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    semaphore.release();
                }
            }, String.valueOf(i)).start();
        }
    }
}

运行结果

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

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

相关文章

Python 基础001 pythonpycharm安装

1 安装python 尽量在官网安装 根据电脑情况下载,下载完需要重启电脑 python安装路径自定义 添加环境变量&#xff08;add path&#xff09;需要勾选&#xff0c;若无勾选&#xff0c;手动更新环境变量 确认python是否安装成功&#xff1a; 方法一&#xff1a;有安装成功&am…

零基础直接上手java跨平台桌面程序,使用javafx(六)查询sqlite数据显示到TableView中

我们使用jdbc查询sqlite的一个表显示到TableView中 在hello-view的onMouseClicked里面填上“openclick2”&#xff0c;然后在HelloController写上openclick2的相关代码FXML protected void openclick2() { }。我们要先配置好sqlite的jdbc驱动&#xff08;略&#xff09;。openc…

代码随想录算法训练营第二十九天【回溯】| 491,46,47

491. Non-decreasing Subsequences 排列用startindex 树枝不去重&#xff0c;树层去重 子集问题结果在结点&#xff08;个数>2&#xff09; class Solution(object):def findSubsequences(self, nums):""":type nums: List[int]:rtype: List[List[int]]&…

如何在网上下载到最新或者历史QGIS各个版本的C++源码

背景&#xff1a; 博主写下这篇文章的时候已经是PyQGIS下二开了两年&#xff0c;开发一些功能必须得去阅读QGIS的C版本源码&#xff0c;还得考虑到QGIS的长期稳定版和最新版的源码区别。 所以如何去下载到QGIS的源码&#xff0c;就成了当务之急。 QGIS3.36.3的C源码长得像这…

KOL营销在时尚、美妆与健康行业的特点解析与应用策略

在当今数字化时代&#xff0c;KOL营销已经成为推动品牌影响力和销售增长的重要策略之一。尤其在时尚、美妆和健康等行业&#xff0c;KOL的影响力和效果尤为显著。本文Nox聚星将和大家详细探讨KOL营销在这些行业中的应用情况、特点以及最佳实践。 一、时尚行业KOL营销 时尚行业…

finalshell创建和使用

1、下载安装 下载地址Finalshell SSH工具,业界最强大的SSH客户机 2、创建连接 点击文件夹新建连接

Struts2 系列漏洞 - S2-003、S2-005

一、前言 前面一篇文章也有提到 struts2 在进入 action 进行逻辑处理前&#xff08;以及逻辑处理后&#xff09;&#xff0c;会进入 18 个拦截器栈中对请求进行必要的处理&#xff08;如果没有自定义拦截器的话&#xff0c;可以在 struts-default.xml 中找到相应的拦截器栈&am…

【学习笔记】使用gcc编译程序并检查依赖的库

编译 gcc echo.c -o app -lfcgi-o app&#xff1a;指定编译后的输出文件名为 app。 -lfcgi&#xff1a;告诉编译器链接 FastCGI 库。 检查 ldd appldd 是一个在 Unix 和类 Unix 系统中用来打印一个已编译的程序所依赖的共享库列表的命令。当你运行 ldd app 命令时&#xff0…

Windows 10 中添加 开机启动 自动运行的程序

Win R 输入 “shell:startup” &#xff0c;回车确定 把 应用的 快捷方式 复制到文件夹中。就会自动开机启动了 参照图&#xff1a;

VLAN配置实验

目录 一、概述 二、组网 三、配置 四、验证 一、概述 以太网是一种基于CSMA/CD的共享通讯介质的数据网络通讯技术。当主机数目较多时会导致冲突严重、广播泛滥、性能显著下降甚至造成网络不可用等问题。 通过交换机可以解决LAN互连虽然可以解决冲突严重的问题&#xff0c;但是仍…

Redis 搭建主从复制、哨兵模式【Windows】

Redis 主从复制模式是一种用于数据冗余和可伸缩性的机制&#xff0c;它允许从服务器&#xff08;Slave&#xff09;从主服务器&#xff08;Master&#xff09;复制数据&#xff0c;从而实现数据的备份和读写分离。以下是关于Redis主从复制模式的详细介绍&#xff1a; 1. 主从复…

电脑U盘管理软件有哪些?精选四款适合企业的U盘管理软件

在当前的数字化时代&#xff0c;电脑U盘作为重要的数据存储和传输工具&#xff0c;其管理显得尤为关键。为了确保U盘数据的安全性和完整性&#xff0c;许多企业和个人都选择使用专业的U盘管理软件。以下是几款值得推荐的电脑U盘管理软件&#xff0c;包括域智盾在内&#xff0c;…

Python网络爬虫4-实战爬取pdf

1.需求背景 爬取松产品中心网站下的家电说明书。这里以冰箱为例&#xff1a;松下电器-冰箱网址 网站分析&#xff1a; 第一步&#xff1a; 点击一个具体的冰箱型号&#xff0c;点击了解更多&#xff0c;会打开此型号电器的详情页面。 第二步&#xff1a;在新打开的详情页面中…

阻塞IO、非阻塞IO、IO多路复用和信号驱动IO简介

一、分类 在UNIX或Liunx下主要有4中IO模型 阻塞IO:最简单、最常用、效率最低 阻塞IO简介和代码示例-CSDN博客当进程执行读操作的时候&#xff0c;如果缓冲区有内容&#xff0c;则继续读取内容向下执行。缓冲区没内容&#xff0c;进程进入休眠态&#xff0c;直到缓冲区中再次…

老徐亲自带队死磕 30 天 IP 公众号价值写作, 邀请你一起玩

* 大家好&#xff0c;我是前端队长。前端程序员&#xff0c;2023年开始玩副业。做过AI绘画&#xff0c;公众号 AI 爆文&#xff0c;AI代写项目&#xff0c;累计变现五位数。 — 老徐的一人企业书籍提到一点&#xff1a;120、完全没基础的同学&#xff0c;玩副业&#xff0c;玩 …

springboot连接多个库

一个SpringBoot项目&#xff0c;同时连接两个数据库&#xff1a;比如一个是Mysql数据库&#xff0c;一个是oracle数据库&#xff08;啥数据库都一样&#xff0c;连接两个同为oracle的数据库&#xff0c;或两个不同的数据库&#xff0c;只需要更改对应的driver-class-name和jdbc…

视觉SLAM14精讲——相机与图像3.2

视觉SLAM14精讲 三维空间刚体运动1.0三维空间刚体运动1.1三维空间刚体运动1.2李群与李代数2.1相机与图像3.1 视觉SLAM14精讲——相机与图像3.2 视觉SLAM14精讲畸变有关重投影误差缩放实际使用 畸变 相机畸变是相机镜头光学缺陷所致的缺陷&#xff0c; 在光学领域这种问题是没…

Apple Intelligence:一文详细解读苹果AI!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

更适合工程师和研究僧的FPGA专项培训课程

各位编程精英er~ 社区打造的FPGA工程师培训班上线后&#xff0c;有不少同学后台私信询问&#xff1a;“能不能出个那种专门针对某个知识点的课程呢&#xff1f;我想针对自己的薄弱点深入学习。” 贴心如我&#xff0c;当然会满足大家的学习需求啦。本周&#xff0c;社区FPGA专…

Anime Girls Pack

动漫女孩包 35个动画&#xff08;就地&#xff09;支持人形。 8情绪。 角色列表&#xff1a;原艾艾琪惠美子惠理文子星薰和子佳子奈子理子凛老师小樱老师津雨僵尸女孩01 下载&#xff1a;​​Unity资源商店链接资源下载链接 效果图&#xff1a;