看懂线程安全

目录:

  1. 线程安全
  2. 线程同步
  3. 同步代码块
  4. 同步方法
  5. Lock锁
  6. 线程状态图
  7. sleep睡眠
  8. 等待和唤醒

1. 线程安全

  • 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样
    的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

我们通过一个案例,演示线程的安全问题:

电影院要卖票,我们模拟电影院的卖票过程。假设要播放的电影是 “葫芦娃大战奥特曼”,本次电影的座位共100个(本 场电影只能卖100张票)。我们来模拟电影院的售票窗口,实现多个窗口同时卖 “葫芦娃大战奥特曼”这场电影票(多个窗口一起卖这100张票) 需要窗口,采用线程对象来模拟;需要票,Runnable接口子类来模拟

模拟票:

public class Ticket implements Runnable {
private int ticket = 100;
/*
* 执行卖票操作
* */
@Override
public void run() {
//每个窗口卖票的操作
//窗口 永远开启
while (true) {
if (ticket > 0) {//有票 可以卖
//出票操作
//使用sleep模拟一下出票时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖:" + ticket--);
}
}
}
}

测试类:

public class Demo {
public static void main(String[] args) {
//创建线程任务对象
Ticket ticket = new Ticket();
//创建三个窗口对象
Thread t1 = new Thread(ticket, "窗口1");
Thread t2 = new Thread(ticket, "窗口2");
Thread t3 = new Thread(ticket, "窗口3");
//同时卖票
t1.start();
t2.start();
t3.start();
}
}

效果图:
在这里插入图片描述

  1. 相同的票数,比如5这张票被卖了3回。
  2. 不存在的票,比如0票与-1票,是不存在的。
  • 这种问题,几个窗口(线程)票数不同步了,这种问题称为线程不安全。

2. 线程同步:

线程同步是为了解决线程安全问题。
Java中提供了同步机制(synchronized)来解决。
根据案例简述:

窗口1线程进入操作的时候,窗口2和窗口3线程只能在外等着,窗口1操作结束,窗口1和窗口2和窗口3才有机会进入代码去执行。也就是说在某个线程修改共享资源的时候,其他线程不能修改该资源,等待修改完毕同步之后,才能去抢夺CPU资源,完成对应的操作,保证了数据的同步性,解决了线程不安全的现象。

有三种方式完成同步操作:

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

3.同步代码块

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

synchronized(同步锁){
需要同步操作的代码
}

对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁

  1. 锁对象 可以是任意类型。
  2. 多个线程对象 要使用同一把锁。

代码演示:

public class Ticket implements Runnable {private int ticket = 100;Object lock = new Object();
//  执行卖票操作@Overridepublic void run() {
//每个窗口卖票的操作
//窗口 永远开启while (true) {synchronized (lock) {if (ticket > 0) {//有票 可以卖
//出票操作
//使用sleep模拟一下出票时间try {Thread.sleep(50);} catch (InterruptedException e) {
// TODO Auto-generated catch blocke.printStackTrace();}
//获取当前线程对象的名字String name = Thread.currentThread().getName();System.out.println(name + "正在卖:" + ticket--);}}}}
}

4.同步方法

  • 同步方法:使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着
    格式:
public synchronized void method(){
可能会产生线程安全问题的代码
}

同步锁是谁?

  • 对于非static方法,同步锁就是this。
  • 对于static方法,我们使用当前方法所在类的字节码对象(类名.class)。

使用同步方法代码如下:

public class Ticket implements Runnable{private int ticket = 100;/** 执行卖票操作*/@Overridepublic void run() {
//每个窗口卖票的操作
//窗口 永远开启while(true){sellTicket();}}/** 锁对象 是 谁调用这个方法 就是谁* 隐含 锁对象 就是 this**/public synchronized void sellTicket(){if(ticket>0){//有票 可以卖
//出票操作
//使用sleep模拟一下出票时间try {Thread.sleep(100);} catch (InterruptedException e) {
// TODO Auto-generated catch blocke.printStackTrace();}
//获取当前线程对象的名字String name = Thread.currentThread().getName();System.out.println(name+"正在卖:"+ticket--);}}
}

5.Lock锁

Lock介绍:

Lock更加灵活,它里面有相应的方法:

  • public void lock() :加同步锁。
  • public void unlock() :释放同步锁。

Lock实现类:

ReentrantLock

Lock使用标准方式

 l.lock(); 获得锁try {操作共享资源的代码} finally {l.unlock();}
public class SaleTicketRunnable implements Runnable {int ticketNum = 100; // 表示100张票Lock l = new ReentrantLock();@Overridepublic void run() {// 2.重写run方法,在run方法中实现这个卖票逻辑String name = Thread.currentThread().getName();while (true) {// 如果票数大于0,就卖一张l.lock(); // 获得锁try {if (ticketNum > 0) {try { // 模拟卖票要花的时间Thread.sleep(10);} catch (InterruptedException e) {}ticketNum--;System.out.println(name + "卖了一张票,剩余: " + ticketNum);} else {// 没有票了,结束循环,停止了卖票break;}} finally {l.unlock(); // 释放锁}}}
}

6. 线程状态:

线程状态图:
在这里插入图片描述

7. 睡眠sleep方法

public static void sleep(long time) 让当前线程进入到睡眠状态,到毫秒后自动醒来继续执行

public class Test{
public static void main(String[] args){
for(int i = 1;i<=5;i++){
Thread.sleep(1000);//主线程执行到sleep方法会休眠1秒后再继续执行。
System.out.println(i)}}
}

8. 等待和唤醒

讲解:

  • public void wait() : 让当前线程进入到等待状态 此方法必须锁对象调用.
  • 等待和唤醒,通常是两个线程之间的事情,一个线程等待,另外一个线程负责唤醒

Object类的方法:

  • void wait​() 导致当前线程等待
  • void notify​() 唤醒正在等待的单个线程

注意: wait​和notify​必须在同步代码块中,使用锁对象来调用

两道面试题:

1.为什么wait和notify方法放在Object

wait​和notify​使用锁对象来调用,任何对象都可以作为锁,所以就放在Object类中

2.sleep和wait的区别

1.sleep睡眠的时候不会释放锁
2.wait等待的时候会释放锁

 public static void main(String[] args) throws InterruptedException {Object obj = new Object();// obj.wait(); // IllegalMonitorStateException: 非法监视状态异常new Thread(new Runnable() {@Overridepublic void run() {synchronized (obj) {try {System.out.println("wait前");obj.wait();System.out.println("wait后");} catch (InterruptedException e) {}}}}).start();Thread.sleep(3000);new Thread(new Runnable() {@Overridepublic void run() {synchronized (obj) {System.out.println("准备唤醒");obj.notify();}}}).start();}

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

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

相关文章

oracle数据库生产,从安装系统到oracle数据库生产环境(centos6.8)搭建

大纲服务器安装JDK配置Oracle数据库安装配置1.安装服务器服务器的安装参考这篇教程关于安装中可能出现的几个问题&#xff0c;在这里进行解决&#xff1a;1、使用u盘安装完后&#xff0c;系统进入GRUB引导&#xff0c;无法启动&#xff1a;解决办法&#xff1a;出现上述状况的原…

详解线程池

概念&#xff1a; 什么是线程池: 线程池是用来存储多线程的容器&#xff0c;是一种处理形式&#xff0c;处理过程中将任务添加到队列&#xff0c;然后在创建线程后自动启动这些任务。 线程池使用和不使用的区别&#xff1a; 因为系统创建线程池的成本很高&#xff0c;会涉及到…

oracle 10g express linux,在Ubuntu下安装Oracle Database 10g Express Edition

Oracle 10g有一款XE版&#xff0c;意为体验版&#xff0c;限制是不支持多CPU和数据库大小不能超过2G(还有其他的什么&#xff0c;不记得了&#xff0c;Oracle官方网站有写)。对于开发的时候调试一下&#xff0c;体验一下还是够用的。关键大小比较适中&#xff0c;安装包200多M。…

oracle硬盘亮黄灯,RH2288H V3服务器硬盘亮黄灯故障处理案例

原标题&#xff1a;RH2288H V3服务器硬盘亮黄灯故障处理案例本文广州诚本将分享RH2288H V3服务器硬盘亮黄灯故障处理案例&#xff0c;希望对大家的工作有所帮助。问题描述某客户新开局的项目&#xff0c;采购一批RH2288H V3的服务器&#xff0c;做RAID时发现其中一台服务器一块…

彻底学会IO流

概述&#xff1a; IO流就是用来处理设备间数据传输问题的.常见的应用: 文件复制; 文件上传; 文件下载IO的数据传输&#xff0c;可以看做是一种数据的流动&#xff0c;按照流动的方向&#xff0c;已内存为参照物&#xff0c;进行读写操作IO可以保存到文件&#xff0c;其实就是内…

一些芯片资料

74hc14d u10 u11 u12 六反相触发器 74HC244 三态八缓冲器 u15 u13 uln2003afwg u16 74HC07 u17 L298N 步进电机驱动芯片 MOS管认知 转载于:https://www.cnblogs.com/legion/p/6908434.html

DP Intro - Tree DP Examples

因为上次比赛sb地把一道树形dp当费用流做了&#xff0c;受了点刺激&#xff0c;用一天时间稍微搞一下树形DP&#xff0c;今后再好好搞一下&#xff09; 基于背包原理的树形DP poj 1947 Rebuilding Roads 题意&#xff1a;给你一棵树,让你求最少剪掉多少条边可以剪出一棵点数为m…

转换流/序列化/反序列化

转换流&#xff1a; 使用转换流可以在一定程度上避免乱码&#xff0c;还可以指定输入输出所使用的字符集 InputStreamReader&#xff1a;是从字节流到字符流的桥梁&#xff0c;父类是Reader OutputStreamWriter&#xff1a;是从字符流到字节流的桥梁&#xff0c;父类是Writer 转…

python+unittest框架整理(一点点学习前辈们的封装思路,一点点成长。。。)

预期框架整理目标&#xff1a; 1.单个用例维护在单个.py文件中可单个执行&#xff0c;也可批量生成组件批量执行 2.对定位参数&#xff0c;定位方法&#xff0c;业务功能脚本&#xff0c;用例脚本&#xff0c;用例批量执行脚本&#xff0c;常用常量进行分层独立&#xff0c;各自…

vs远程编译linux程序,使用Visual Studio 2015远程调试Linux程序

##安装 Visual Studio 2015安装时注意将跨平台移动开发->Visual C移动开发->Viaual C Android 开发的选项勾上##安装PUTTYVisual Studio依赖putty中的plink来连接Linux机器并发送命令##使用首先在Visual Studio中新建一个空项目这里是列表文本接下来将代码导入到这个空项…

都在说反射,反射到底是什么

概念&#xff1a; 什么是反射? 利用反射可以无视修饰符获取类里面所有的属性和方法对于任何对象&#xff0c;都能够调用它的方法和属性&#xff0c;这种动态获取信息以及动态调用对象方法的功能称为Java的反射 反射的应用场景? 常见的有&#xff1a; idea的智能提示、框架等…

LaunchScreen原理

会自动加载LaunchScreen是因为在Target当中,指定了Launch Screen file 它的底层实现其实把LaunchScreen上的东西,生成了一张图片,然后把这张图片设为程序的启动图片.可以进入沙盒当中查看,查看方法,找到应用程序根目录.获取方法: NSLog("%",NSHomeDirectory());打印出…

Mac - 苹果电脑mac系统释放硬盘空间方法汇总

硬盘空间是大家最头痛的一个问题&#xff0c;大家在硬盘空间变小的时候怎么腾空间的呢&#xff1f;下面为大家分享7个mac系统释放空间的高级方法&#xff0c;大家赶紧来收了&#xff01; mac系统释放硬盘空间方法&#xff1a; 方法一&#xff1a;删除Emacs——可以节省出60MB的…

XML语言

XML&#xff1a; XML是可扩展的标记语言 标记语言: 通过标签来描述数据的一门语言(标签有时我们也将其称之为元素) 可扩展&#xff1a;标签的名字是可以自定义的,XML文件是由很多标签组成的,而标签名是可以自定义的 xml学习网站https://www.w3school.com.cn/x.asp 作用&#xf…

xml中的Document和Attribute

1.Document 导入dom4j的步骤 去官网下载 zip 包。http://www.dom4j.org/ 在项目中创建一个文件夹&#xff1a;lib将dom4j-2.1.1.jar文件复制到 lib 文件夹在jar文件上点右键&#xff0c;选择 Add as Library -> 点击OK在类中导包使用 得到Document对象 步骤&#xff1a;…

XPath表达式

什么是XPath XPath&#xff1a;路径表达式 作用&#xff1a;在DOM解析XML时&#xff0c;通过XPath表达让解析更加简单 XPath表达式分类 绝对路径相对路径全文搜索属性查找 什么是Node对象 DOM树中的每个节点就是Node dom4j中与XPath相关的方法 注&#xff1a;使用XPat…

最详细MySQL的安装与介绍Windows

数据库的安装&#xff1a; 打开下载的mysql安装⽂件双击解压缩&#xff0c;运⾏“mysql-5.5.40-win32.msi”。 选择安装类型&#xff0c;有“Typical&#xff08;默认&#xff09;”、“Complete&#xff08;完全&#xff09;”、“Custom&#xff08;⽤户⾃定义&#xff09;”…

读懂基础机器学习算法

本篇内容主要是面向机器学习初学者&#xff0c;介绍常见的机器学习算法&#xff0c;当然&#xff0c;欢迎同行交流。 哲学要回答的基本问题是从哪里来、我是谁、到哪里去&#xff0c;寻找答案的过程或许可以借鉴机器学习的套路&#xff1a;组织数据->挖掘知识->预测未来。…

在c语言中有函数leapyear定义如下,职业教育概论——职业教育的发展历史超星尔雅答案题库...

职业职业展历有时候,文学造诣高的中国诗歌翻译者在用词华丽方面超过莎士比亚。有int型变量x&#xff0c;教育教育i&#xff0c;j&#xff0c;k&#xff0c;则表达式x(i5,j6,k7)的值为( )从数据表student中查询张姓的所有学生&#xff0c;概论正确的SQL语句是( )史超世界上第一个…

tomcat安装启动配置

服务器&#xff1a; 服务器的概念非常的广泛&#xff0c;它可以指代一台特殊的计算机&#xff08;相比普通计算机运行更快、负载更高、价格更贵&#xff09;&#xff0c;也可以指代用于部署网站的应用。我们这里说的服务器&#xff0c;其实是web服务器&#xff0c;或者应用服务…