当前位置: 首页 > news >正文

线程安全问题

目录

一、线程安全

二、线程安全问题

三、线程安全 

1.同步代码块 

2.同步方法

3.Lock锁

3.1常用方法:

 3.2 死锁

3.3 练习:

四、生产者和消费者(线程通信问题)


一、线程安全

如果有多个线程在同时运行,而这些线程可能会同时运行这些代码,程序每次运行的结果和单线程每次运行的结果是一样的,就是线程安全的,反之则是非线程安全的。

二、线程安全问题

现在有如下场景,电影院要卖票,我们模拟电影院的网上卖票过程。本次电影的座位共
100个(本场电影只能卖100张票)。我们来模拟电影院的售票窗口,实现多个窗口同时卖这
场电影票(多个窗口一起卖这100张票)。

售票窗口我们可以用线程来模拟。票数我们可以在 Runnable 的实现类中设定。

package thread;public class Demo {public static void main(String[] args) {SellTicket sellTicket=new SellTicket();Thread t1 = new Thread(sellTicket,"1号窗口");Thread t2 = new Thread(sellTicket,"2号窗口");Thread t3 = new Thread(sellTicket,"3号窗口");Thread t4 = new Thread(sellTicket,"4号窗口");Thread t5 = new Thread(sellTicket,"5号窗口");t1.start();t2.start();t3.start();t4.start();t5.start();}
}
class SellTicket implements Runnable {private int tickets=100;//总票数private Object object=new Object();//锁@Overridepublic void run() {//售票窗口一直开放while (true){//同步synchronized (object){//还有票if (tickets>0){try {Thread.sleep(100);//模拟出票} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName()+"正在出售第【"+tickets--+"】张票");}}}}
}

线程安全问题都是由全局变量及静态变量引起的, 若每个线程中对全局变量及静态变量只有读操作、没有写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

安全问题出现的条件:

  • 多线程环境
  • 共享数据
  • 有多条语句操作共享数据 

 如果解决多线程安全问题?

  • 基本思想:让程序处在没有安全问题的环境中
  • 怎么解决:把多条语句操作共享数据的代码锁起来,使得在任何时刻只能有一个线程执行该代码
  • Java提供了同步的方式(synchronized)

三、线程安全 

当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题。要解决多线程并发访问同一资源的问题:也就是解决重复票和不存在票问题,Java中提供了同步机制来解决。 

也就是说一号窗口线程进入操作的时候,其他线程只能在外等着,一号窗口操作结束,其他代码(也包括一号窗口)才有机会去执行。也就是说在某个线程修改共享资源的时候,其他线程不能修改该资源,等待修改完毕同步之后,才能去抢夺CPU资源,完成对应的操作。

为了保证每个线程都能执行原子操作,Java提供了同步机制。

原子操作时不需要synchronized的,所谓原子操作是不能被线程调度机制打断的操作,这种操作一旦开始执行,就一直运行到结束,中间不会发生切换。

如果这个操作所处的层的更高层不能发现其内部实现和结构,那么这个操作就是一个原子操作。

原子操作可以是一个步骤,也可以是多个步骤,但是它的顺序不能被打乱,而且不能被切割只执行其中的一部分。

将整个操作视作一个整体是原子性的核心特征。

Java提供了三种同步机制:

  1. 同步代码块
  2. 同步方法
  3. 锁机制 

1.同步代码块 

synchronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。

synchronized(同步锁){//同步的代码
}

同步锁:对象的同步锁只是一个概念,可以想象成在任何一个对象上标记了一个锁。

2.同步方法

使用synchronized修饰的方法,叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。

public synchronized void method(){// 可能出现安全问题的代码
}
或者
synchronized public void method(){//可能出现安全问题的代码
}

同步方法中的同步锁是什么?

对于实例方法,同步锁就是this。

对于static方法,同步锁就是方法所在类的字节码文件(类名.class)。

3.Lock锁

java.util.concurrent.locks.Lock机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,同步方法/同步代码块有的功能Lock都有,除此之外更强大,更体现面向对象。在JDK5引入了ReentrantLock,ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中总是用皮率很高的一个锁,支持重入性,表示能够对共享资源重复加锁,即当前线程获取该锁后再次获取不会被阻塞,支持公平锁和非公平锁两种方式。

3.1常用方法:

  • public void lock();   //加同步锁
  • public void unlock();  //释放同步锁

 3.2 死锁

  • 概述

 线程死锁是指由于两个或多个线程互相持有对方所需要的资源 ,导致这些线程处于等待状态,无法前往执行。

  • 什么情况下会产生死锁?
  1. 资源有限
  2. 同步嵌套 
package thread;public class Demo04 {public static void main(String[] args) {Object A = new Object();Object B = new Object();new Thread(()->{while (true){synchronized (A){synchronized (B){System.out.println("线程1");}}}}).start();new Thread(()->{while (true){synchronized (B){synchronized (A){System.out.println("线程2");}}}}).start();}
}

3.3 练习:


写5个线程对 i 进行 100次 加一操作,再写 5 个线程对 i 进行100次 减一操作,输出结果.

package thread;import java.util.concurrent.CountDownLatch;/*** 写5个线程对 i 进行 100次 加一操作,再写 5 个线程对 i 进行100次 减一操作,输出结果*/
public class Five {
//    public static int i=0;public static void main(String[] args) {//第一种
//        Thread[] t1 = new Thread[5];//加1的线程
//        Thread[] t2 = new Thread[5];//减1的线程
//
//        //加1的五个线程
//        for (int j = 0; j < 5; j++) {
//            t1[j]=new Thread(()->{
//                synchronized (Five.class){
//                    for (int k = 0; k < 1000; k++) {
//                        i++;
//                    }
//                }
//
//            });
//            t1[j].start();
//        }
//
//        //减1的五个线程
//        for (int j = 0; j < 5; j++) {
//            t2[j]=new Thread(()->{
//                synchronized (Five.class){
//                    for (int k = 0; k <1000; k++) {
//                        i--;
//                    }
//                }
//
//            });
//            t2[j].start();
//        }
//
//        for (int j = 0; j < 5; j++) {
//            try {
//                t1[j].join();
//                t2[j].join();
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
//        }
//        System.out.println(Thread.currentThread().getName()+":"+i);Operate operate = new Operate();//线程计数CountDownLatch countDownLatch = new CountDownLatch(10);//定义Runnable对向执行加1操作Runnable addRun=()->{for (int j = 0; j < 100; j++) {operate.add();}//减少计数器的值countDownLatch.countDown();};//定义Runnable对向执行减1操作Runnable subRun=()->{for (int j = 0; j < 100; j++) {operate.sub();}countDownLatch.countDown();};for (int j = 0; j < 5; j++) {new Thread(addRun).start();}for (int j = 0; j < 5; j++) {new Thread(subRun).start();}try {countDownLatch.await();//等待线程数为0,说明十个线程都执行结束了} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(operate.getI());}
}
class Operate{private int i=0;public void add(){synchronized (this){i++;}}public void sub(){synchronized (this){i--;}}public int getI(){return i;}
}

四、生产者和消费者(线程通信问题)

  • 概述 

生产者消费者模式是一种十分经典的多线程协作模式。

所谓生产者消费者问题,实际上主要包含了两类线程:

一种是生产者线程用于生产数据

一种是消费者线程用于消费数据

为了解耦生产者和消费者的关系,通常会采用共享的数据区域,就像是一个仓库。

生产者生产数据之后直接放到共享数据区中,并不需要关心消费者的行为

消费者只需要在共享数据区中去获取数据,并不需要关心生产者的行为。

调用wait()/notify()/notifyAll()方法时必须在同步方法/同步代码块中调用 

package thread;import java.time.LocalDateTime;/*** 线程间操作的必要性* 生产者消费者问题*/
public class Demo07 {public static void main(String[] args) {Cook cook = Cook.getCOOK();//厨师线程Maker maker = new Maker(cook, "邹厨师");//顾客Eater e1 = new Eater(cook,"浩哥");Eater e2 = new Eater(cook, "龙哥");Eater e3 = new Eater(cook, "王亮");maker.start();e1.start();e2.start();e3.start();}
}
//厨师类
class Cook{private String bread;//面包private static final Cook cook=new Cook();private Cook(){}public static Cook getCOOK() {return cook;}//同步  制作面包public synchronized void make(){if (bread!=null){try {System.out.println(Thread.currentThread().getName()+"睡了");wait();System.out.println(Thread.currentThread().getName()+"醒了");} catch (InterruptedException e) {throw new RuntimeException(e);}}//制作面包的过程try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}bread= LocalDateTime.now().toString();notify();System.out.println(Thread.currentThread().getName()+"做了一个面包"+bread);}//吃public synchronized void eat(){if (bread==null){try {System.out.println(Thread.currentThread().getName()+"睡了");wait();System.out.println(Thread.currentThread().getName()+"醒了");} catch (InterruptedException e) {throw new RuntimeException(e);}}else {try {//吃面包的过程Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName()+"吃了"+bread);bread=null;notifyAll();//确保把厨师唤醒}}
}
//顾客类---主要是吃
class Eater extends Thread{Cook cook;public Eater(Cook cook,String name) {super(name);this.cook = cook;}@Overridepublic void run() {while (true){cook.eat();}}
}
//制作面包的类
class Maker extends Thread{Cook cook;public Maker(Cook cook,String name){super(name);this.cook=cook;}@Overridepublic void run() {while (true){cook.make();}}
}

相关文章:

线程安全问题

目录 一、线程安全 二、线程安全问题 三、线程安全 1.同步代码块 2.同步方法 3.Lock锁 3.1常用方法&#xff1a; 3.2 死锁 3.3 练习&#xff1a; 四、生产者和消费者&#xff08;线程通信问题&#xff09; 一、线程安全 如果有多个线程在同时运行&#xff0c;而这些…...

【力扣每日一题】2023.9.18 打家劫舍Ⅲ

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 今天是打家劫舍3&#xff0c;明天估计就是打家劫舍4了。 今天的打家劫舍不太一样&#xff0c;改成二叉树了&#xff0c;不过规则没有变&…...

Docker基础学习

Docker 学习目标&#xff1a; 掌握Docker基础知识&#xff0c;能够理解Docker镜像与容器的概念 完成Docker安装与启动 掌握Docker镜像与容器相关命令 掌握Tomcat Nginx 等软件的常用应用的安装 掌握docker迁移与备份相关命令 能够运用Dockerfile编写创建容器的脚本 能够…...

esbuild中文文档-路径解析配置项(Path resolution - Alias、Conditions)

文章目录 路径解析配置项 Path resolution别名 Alias条件解析 Conditionsconditions是如何工作的 结语 哈喽&#xff0c;大家好&#xff01;我是「励志前端小黑哥」&#xff0c;我带着最新发布的文章又来了&#xff01; 老规矩&#xff0c;小手动起来~点赞关注不迷路&#xff0…...

您的应用存在隐藏最近任务列表名称的行为,不符合华为应用市场审核标准

最近各家应用市场&#xff0c;唯独华为审核被拒了。。理由是您的应用存在隐藏最近任务列表名称的行为&#xff0c;不符合华为应用市场审核标准。 根据华为给出的视频&#xff0c;app在任务队列&#xff08;也就是俗称的安卓多任务管理后台&#xff09;不显示应用名。因为我们ap…...

Spring的 webFlux 和 webMVC

看到一个测评文章&#xff0c;并发在300的时候webMVC 和 webFlux的处理能力不相上下&#xff0c; 当并发达到3000的时候, webFlux明显优于webMVC, 有图有真相&#xff0c; 我信了. webMVC 是 one-request-one thread 堵塞模式, flux是非阻塞模式&#xff0c; 是spring家族系列…...

【洛谷算法题】P5706-再分肥宅水【入门1顺序结构】

&#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5706-再分肥宅水【入门1顺序结构】&#x1f30f;题目描述&#x1f30f;输入格式…...

android studio环境搭建让你的开发之旅更加简单

示例示例Android Studio环境搭建&#xff1a;下载并安装Android Studio&#xff1a;从官网下载Android Studio&#xff0c;然后双击安装文件&#xff0c;按照提示进行安装&#xff0c;安装完成之后&#xff0c;可以在桌面上找到Android Studio的快捷方式。 Android Studio环境…...

Java面试_并发编程_线程基础

Java面试_并发编程_线程基础 线程基础线程和进程的区别(出现频率: 3⭐)并行和并发的区别(出现频率: 2⭐)线程的创建(出现频率: 4⭐)线程的状态(出现频率: 4⭐)让线程按顺序执行(出现频率: 3⭐)notify()和notifyAll()有什么区别(出现频率: 2⭐)wait方法和sleep方法的区别(出现频…...

基于Java的高校实习管理系统设计与实现(亮点:实习记录、实习打分、实习作业,功能新颖、老师没见过、当场唬住!)

高校实习管理系统 一、前言二、我的优势2.1 自己的网站2.2 自己的小程序&#xff08;小蔡coding&#xff09;2.3 有保障的售后2.4 福利 三、开发环境与技术3.1 MySQL数据库3.2 Vue前端技术3.3 Spring Boot框架3.4 微信小程序 四、功能设计4.1 主要功能描述 五、系统主要功能5.1…...

傅里叶变换

傅里叶变换常用于缺陷检测项目&#xff0c;对于一些背景偏暗&#xff0c;对比度不明显的场景&#xff0c;傅里叶变换可以起到提升对比度的效果。傅里叶变换从频域角度来处理&#xff0c;对于一些图像像素尺寸大的图像&#xff0c;算法时间往往时间达到1s以上&#xff0c;对于一…...

Vue Grid Layout -️ 适用Vue.js的栅格布局系统,在vue3+上使用

文章目录 1、官网简介2、在vue3中使用1)、需要导入vue3支持的版本插件2)、在mian.js里引入&#xff1a;3)、在组件中使用 3、layout布局的计算逻辑4、 gridLayout 的属性 该栅格系统目前对 vue2 的支持是最好的&#xff0c;vue3 是需要用插件支持的&#xff0c;会在小节详细讲解…...

Electron(v26.2.1)无法加载React Developer Tools(v4.28.0)

一开始按照electron官网上的 开发者工具扩展 教程设置React Developer Tools时&#xff0c;重启项目后并没有按照预期成功加载React Developer Tools&#xff0c;而且控制台报错&#xff1a; Permission scripting is unknown or URL pattern is malformed.查了下原因是因为Re…...

网站降权的康复办法(详解百度SEO数据分析)

随着搜索引擎算法的不断升级&#xff0c;很多网站在SEO优化过程中遭遇到降权的情况。如果您的网站也遭遇到了类似的问题&#xff0c;不必惊慌失措。本文将为您详细介绍网站降权恢复的方法&#xff0c;包括百度SEO数据分析、网站收录少的5个原因、网站被降权的6个因素以及百度SE…...

非对称加密、解密原理及openssl中的RSA示例代码

一、【原理简介】非对称加密 非对称加密&#xff0c;也被称为公钥加密&#xff0c;其中使用一对相关的密钥&#xff1a;一个公钥和一个私钥。公钥用于加密数据&#xff0c;私钥用于解密数据。公钥可以公开分享&#xff0c;而私钥必须保密。 密钥生成: 当一个用户或设备希望使用…...

基于springboot漫画管理系统springboot001

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&…...

【探索C++】string类详解

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言&#xff0c;数据结构&#xff0c;Linux基础&#xff0c;ARM开发板&#xff0c;网络编程等领域UP&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff0…...

python 第一次作业

1.使用turtle换一个五环 2.设计这样一个程序&#xff1a;输入一个数字 判断它是不是一个质数 使用turtle换一个五环&#xff1a; >>> import turtle #导入模块 >>> turtle.width(10) #设置圆圈宽度 >>> turtle.color("blue&qu…...

个人博客网站一揽子:Docker建站(Nginx、Wordpress、MySql)

前言 既然安装了Docker&#xff0c;那就不妨建立一个自己的博客网站。实现内外网隔离网站部署&#xff0c;更安全。 1.创建Docker子网络 首先创建一个Docker虚拟子网&#xff1a; sudo docker network create wpnt检查是否建立成功&#xff1a; sudo docker network ls最后…...

Unity 课时 4 : No.4 模拟面试题

课时 4 : No.4 模拟面试题 C# 1. 请说明字符串中 string str null string str “” string str string.Empty 三者的区别 第一个未作初始化没有值, 第二个为空字符串, 答案&#xff1a; str null 在堆中没有分配内存地址 str "" 和 string.Empty 一样都是…...

Golang 基础面试题 01

Golang 面试题合集.png 背景 在之前的文章中分享了 k8s 相关的面试题&#xff0c;本文我们重点来讨论和 k8s 密切相关的 Go 语言面试题。 这几年随着云原生的兴起&#xff0c;大部分后端开发者&#xff0c;特别是 Java 开发者都或多或少的想学习一些 Go 相关的技能&#xff0c;…...

007-第一代软件需求整理

第一代软件需求整理 文章目录 第一代软件需求整理项目介绍需求来源需求来源1&#xff1a;竞品软件分析需求来源2&#xff1a;医生&#xff08;市场&#xff09;需求来源3&#xff1a;项目组内部需求来源4&#xff1a;软件组内部需求来源5&#xff1a;软件开发成员需求来源6&…...

XMLHttpRequest介绍

目录 一、介绍1.创建 XMLHttpRequest2.初始化3.发送请求4.获取响应5.响应类型 二、发送GET请求示例三、发送POST请求示例四、发送POST请求下载文件示例五、发送POST请求上传文件示例 一、介绍 1.创建 XMLHttpRequest let xhr new XMLHttpRequest();2.初始化 xhr.open(metho…...

阿里云无影云电脑和传统PC有什么区别?

阿里云无影云电脑和传统电脑PC有什么区别&#xff1f;区别大了&#xff0c;无影云电脑是云端的桌面服务&#xff0c;传统PC是本地的硬件计算机&#xff0c;无影云电脑的数据是保存在云端&#xff0c;本地传统PC的数据是保存在本地客户端&#xff0c;阿里云百科分享阿里云无影云…...

基于matlab实现的船舶横摇运动仿真程序

完整程序&#xff1a; clc clear syms w we; w0.4:0.05:1.6;mu90;v6;%kb1;kt1;%航速6m/s&#xff0c;航向90度&#xff0c;即横浪&#xff0c;cos(90)0 T3;B10;Sw0.785;%船宽10米&#xff0c;吃水3米,水线面系数假设为0.785 weww.^2.*v/9.8; for i1:24 delta_we(i)we(i1)-…...

Java手写二叉索引树和二叉索引树应用拓展案例

Java手写二叉索引树和二叉索引树应用拓展案例 1. 算法思维导图 以下为二叉索引树的实现原理的思维导图&#xff0c;使用Mermanid代码表示&#xff1a; #mermaid-svg-raMRIu7t3H33MKh1 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#…...

大数据知识点之大数据5V特征

大数据的特征可以浓缩为五个英文单词&#xff0c;Volume(大量&#xff09;、Variety(多样性&#xff09;、Velocity(速度&#xff09;、Value(价值&#xff09;、Veracity(准确性&#xff09;。因为是5个特征都是以“V”开头的英文单词&#xff0c;又叫大数据5V特征。 概述&…...

Java的Socket通信的断网重连的正确写法

Java的Socket通信的断网重连的正确写法 Socket通信的断网重连介绍客户端与服务端源码演示截图本地演示服务器演示演示截图 总结 Socket通信的断网重连介绍 针对于已经建立通信的客户端与服务器&#xff0c;当客户端与服务器因为网络问题导致网络不通而断开连接了或者由于服务器…...

Rocketmq--消息发送和接收演示

使用Java代码来演示消息的发送和接收 <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.0.2</version> </dependency> 1 发送消息 消息发送步骤: 创建…...

ArcGIS Pro将SHP文件转CAD并保留图层名称

相信大家应该都使用过ArcGIS将SHP文件转CAD格式&#xff0c;转换过后所有的要素都在一个图层内&#xff0c;那么有没有办法将SHP文件某个字段的值作为CAD的图层名字呢&#xff0c;答案是肯定的&#xff0c;这里就为大家介绍一下ArcGIS Pro转CAD文件并且保留图层名称的方法&…...

wordpress主题 missoften/如何被百度收录

【CF932E】Team Work 题意&#xff1a;求$\sum\limits_{i1}^nC_n^ii^k$&#xff0c;答案模$10^97$。$n\le 10^9,k\le 5000$。 【BZOJ5093】图的价值 题意&#xff1a;“简单无向图”是指无重边、无自环的无向图&#xff08;不一定连通&#xff09;。一个带标号的图的价值定义为…...

最好的网站建设价格/2022年国际十大新闻

Demo: ma125120.github.io/ma-dom/test… 本方法主要使用了 Range 对象和HTML5的Selection API&#xff0c;经过测试&#xff0c;本方法在主流浏览器如谷歌浏览器、火狐浏览器、360安全浏览器、搜狗高速浏览器中均运行良好。 先附上大家最想看的代码&#xff1a; function copy…...

自己电脑上做的网站 怎么让别人看/杭州网站建设公司

将下面的程序补充完整&#xff08;包括定义函数&#xff09;&#xff0c;使其能够完成图示的功能。请使用已有程序的风格。/* * Copyright (c) 2014,烟台大学计算机学院 * All right reserved. * 作者&#xff1a;邵帅 * 文件&#xff1a;demo.cpp * 完成时间&#xff1a;2014年…...

英语网站大全免费/市场调研报告怎么写的

使用JavaScript开发IE浏览器本地插件实例 投稿&#xff1a;junjie 字体&#xff1a;[增加 减小] 类型&#xff1a;转载 时间&#xff1a;2015-02-18 我要评论 这篇文章主要介绍了使用JavaScript开发IE浏览器本地插件实例,本文讲解使用JS注册表的方式开发一个IE浏览器本地插件,需…...

手机h5免费模板网站/百度认证平台

变差函数是Motheron在1965年提出的一种矩估计方法&#xff0c;为区域化变量的增量平方的数学期望&#xff0c;也就是区域化变量的增量的方差&#xff0c;很多学者直接将半变差函数称之为变差函数。变差函数是地统计学特有的研究工具&#xff0c;不仅能够表征区域化变量的空间结…...

政府大型网站建设/百度客服转人工

&#xfeff;&#xfeff;Lex自动地表示把输入串词法结构的正规式及相应的动作转换成一个宿主语言的程序&#xff0c;即词法分析程序&#xff0c;它有一个固定的名字yyler&#xff0c;在这里yyler是一个C语言的程序。Yylex将识别出输入串中的词形&#xff0c;并且在识别出某词形…...