这里写目录标题

  • 前言
  • 线程安全
  • 线程同步
    • 同步代码块格式:
    • 同步方法的格式
    • 静态同步方法
    • 同步的好处和弊端
  • 线程死锁
  • 生产者/消费者

前言

为什么要学习线程安全,举个例子,假设我们有1000块钱,呢么我们在取钱时,取了两次钱,一次取了100元,按照之前的知识,剩下多少钱呢,800吗?不,900元,因为都是两次都是1000-100,而我们需要的是,第一次取100,我们还剩900,第二次取100,是在900的基础上减100,这就是线程安全

  • 本节也就是线程安全引出的知识点
    *

线程安全

  • 临界资源:同一个数据或对象每次只能允许一个线程进行方法操作
  • 原子操作:不可分割的多部操作被视为一个整体。其顺序和步骤不可打乱或缺省

在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。

线程同步

安全问题出现的条件

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

怎么实现呢?

  • 把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可

  • Java提供了同步代码块的方式来解决

同步代码块格式:

synchronized(任意对象) { 多条语句操作共享数据的代码
}

synchronized(任意对象):就相当于给代码加锁了,任意对象就可以看成是一把锁

同步方法的格式

同步方法:就是把synchronized关键字加到方法上

修饰符 synchronized 返回值类型 方法名(方法参数) { 方法体;
}

同步方法的锁对象是什么呢?

​ this

静态同步方法

同步静态方法:就是把synchronized关键字加到静态方法上

修饰符 static synchronized 返回值类型 方法名(方法参数) { 方法体;
}

同步静态方法的锁对象是什么呢?

​ 类名.class

同步的好处和弊端

  • 好处:解决了多线程的数据安全问题

  • 弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

线程死锁

  • 概述

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

  • 什么情况下会产生死锁

    1. 资源有限
    2. 同步嵌套
  • 代码演示

public class Demo {public static void main(String[] args) {Object objA = new Object();Object objB = new Object();new Thread(()->{while(true){synchronized (objA){//线程一synchronized (objB){System.out.println("张三正在走路");}}}}).start();new Thread(()->{while(true){synchronized (objB){//线程二synchronized (objA){System.out.println("李四  正在走路");}}}}).start();}
}

生产者/消费者

能够有效的解决死锁的问题

  • 概述

    生产者消费者模式是一个十分经典的多线程协作的模式,弄懂生产者消费者问题能够让我们对多线程编程的理解更加深刻。

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

    ​ 一类是生产者线程用于生产数据

    ​ 一类是消费者线程用于消费数据

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

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

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

  • Object类的等待和唤醒方法

    方法名 说明
    void wait() 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法
    void notify() 唤醒正在等待对象监视器的单个线程
    void notifyAll() 唤醒正在等待对象监视器的所有线程
public class Desk {//定义一个标记//true 就表示桌子上有汉堡包的,此时允许吃货执行//false 就表示桌子上没有汉堡包的,此时允许厨师执行//public static boolean flag = false;private boolean flag;//汉堡包的总数量//public static int count = 10;//以后我们在使用这种必须有默认值的变量// private int count = 10;private int count;//锁对象//public static final Object lock = new Object();private final Object lock = new Object();public Desk() {this(false,10); // 在空参内部调用带参,对成员变量进行赋值,之后就可以直接使用成员变量了}public Desk(boolean flag, int count) {this.flag = flag;this.count = count;}public boolean isFlag() {return flag;}public void setFlag(boolean flag) {this.flag = flag;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}public Object getLock() {return lock;}@Overridepublic String toString() {return "Desk{" +"flag=" + flag +", count=" + count +", lock=" + lock +'}';}
}public class Cooker extends Thread {private Desk desk;public Cooker(Desk desk) {this.desk = desk;}
//    生产者步骤:
//            1,判断桌子上是否有汉堡包
//    如果有就等待,如果没有才生产。
//            2,把汉堡包放在桌子上。
//            3,叫醒等待的消费者开吃。@Overridepublic void run() {while(true){synchronized (desk.getLock()){if(desk.getCount() == 0){break;}else{//System.out.println("验证一下是否执行了");if(!desk.isFlag()){//生产System.out.println("厨师正在生产汉堡包");desk.setFlag(true);desk.getLock().notifyAll();}else{try {desk.getLock().wait();} catch (InterruptedException e) {e.printStackTrace();}}}}}}
}public class Foodie extends Thread {private Desk desk;public Foodie(Desk desk) {this.desk = desk;}@Overridepublic void run() {//        1,判断桌子上是否有汉堡包。
//        2,如果没有就等待。
//        3,如果有就开吃
//        4,吃完之后,桌子上的汉堡包就没有了
//                叫醒等待的生产者继续生产
//        汉堡包的总数量减一//套路://1. while(true)死循环//2. synchronized 锁,锁对象要唯一//3. 判断,共享数据是否结束. 结束//4. 判断,共享数据是否结束. 没有结束while(true){synchronized (desk.getLock()){if(desk.getCount() == 0){break;}else{//System.out.println("验证一下是否执行了");if(desk.isFlag()){//有System.out.println("吃货在吃汉堡包");desk.setFlag(false);desk.getLock().notifyAll();desk.setCount(desk.getCount() - 1);}else{//没有就等待//使用什么对象当做锁,那么就必须用这个对象去调用等待和唤醒的方法.try {desk.getLock().wait();} catch (InterruptedException e) {e.printStackTrace();}}}}}}
}public class Demo {public static void main(String[] args) {/*消费者步骤:1,判断桌子上是否有汉堡包。2,如果没有就等待。3,如果有就开吃4,吃完之后,桌子上的汉堡包就没有了叫醒等待的生产者继续生产汉堡包的总数量减一*//*生产者步骤:1,判断桌子上是否有汉堡包如果有就等待,如果没有才生产。2,把汉堡包放在桌子上。3,叫醒等待的消费者开吃。*/Desk desk = new Desk();Foodie f = new Foodie(desk);Cooker c = new Cooker(desk);f.start();c.start();}
}

好的,本节到此结束,做个小结,本节我们学到了

  1. 线程安全
  2. 为了实现线程安全-》线程同步(synchronized)
  3. 但是线程同步会导致一个严重的问题=》线程死锁
  4. 怎么解决线程死锁-》生产者/消费者

java多线程-线程安全相关推荐

  1. Java多线程——线程的优先级和生命周期

    Java多线程--线程的优先级和生命周期 摘要:本文主要介绍了线程的优先级以及线程有哪些生命周期. 部分内容来自以下博客: https://www.cnblogs.com/sunddenly/p/41 ...

  2. java多线程 线程安全_Java中的线程安全

    java多线程 线程安全 Thread Safety in Java is a very important topic. Java provides multi-threaded environme ...

  3. java多线程-线程的停止【interrupt】

    java多线程-线程的停止 文章目录 java多线程-线程的停止 线程停止的原理 如何正确停止线程 在普通情况下停止线程 代码展示 在阻塞情况下停止线程 代码展示 线程在每次迭代后都阻塞 代码展示 停 ...

  4. Java 多线程线程安全(面试概念解答二)

    Java 多线程线程安全 什么是线程安全? 为什么有线程安全问题? 线程安全解决办法? 同步代码块 同步函数 静态同步函数 多线程死锁 多线程的三大特性 原子性 可见性 有序性 Java内存模型 Vo ...

  5. JAVA --- 多线程 -- 线程的创建

    JAVA - 多线程 – 线程的创建 线程的概念: 说起线程,先说程序和进程,多任务的概念. 程序(program):是指令和数据的有序集合,本身没有任何运行的含义,是一个静态的概念. 进程(proc ...

  6. Java多线程-线程的同步与锁

    一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. package ...

  7. Java多线程 ——线程基础和锁锁锁

    Java多线程(一) 一.线程的定义 二.Synchronize线程同步 三.偏向锁.自旋锁.重量级锁 四.volatile关键字 4.1.普通变量运算的物理意义 4.2.有无解决的方案 4.3.vo ...

  8. 【Java系列】(四)Java多线程---线程安全

    前言: 记得大一刚学Java的时候,老师带着我们做了一个局域网聊天室,用到了AWT.Socket.多线程.I/O,编写的客户端和服务器,当时做出来很兴奋,回学校给同学们演示,感觉自己好NB,呵呵,扯远 ...

  9. Java多线程-线程的创建(Thread类的基本使用)

    文章目录 一. 线程和Thread类 1. 线程和Thread类 1.1 Thread类的构造方法 1.2 启用线程的相关方法 2. 创建第一个Java多线程程序 3. 使用Runnable对象创建线 ...

  10. Java多线程——线程池的饥饿现象

    概述 定长线程池的使用过程中会存在饥饿现象,也就是当多线程情况下,当池中所有线程都被占用后,被占用的线程又需要空闲线程去进行下一步的操作,此时又获取不到池中空闲的线程,此时就出现了饥饿现象. 示例 p ...

最新文章

  1. 服务器与本地时间的倒计时
  2. 算法 快速求一个整数的7倍
  3. sencha touch Model validations 自定义验证 二选一输入验证、重复验证、时间验证、比较验证、条件验证(2015-1-14)...
  4. LeetCode题组:第836题-矩形叠加
  5. Windows:chm 文件打开出现“已取消到该网页的导航”的解决方案
  6. 白领体检异常率连年走高,这5本书教你怎样科学养生
  7. Java请求参数检查,Java如何检查servlet请求中是否存在参数?
  8. 自动驾驶算法-滤波器系列(三)——不同运动模型(CV、CA、CTRV、CTRA)的建模和推导
  9. linux 安装mysql 云盘_linux下 安装mysql教程
  10. TableView全展开实现ContentSizedTableView
  11. XP_cmdshell
  12. 产品经理如何进行复盘总结
  13. 常见七种逻辑门真值表
  14. JMeter察看结果树响应数据都是相同原因
  15. 清华大学赵志磊--基于thinkPHP6框架的Excel表格导入和导出
  16. 转:张五常:比知识更重要的,是思维方式
  17. 如何用虚拟机搭win建服务器,windows10系统下使用VMware搭建虚拟机超详细的图文教程...
  18. 动力节点Dubbo学习笔记
  19. 微信小程序接入关联微信公众号official-account方案总结
  20. 腾讯云~安装ActiveMQ

热门文章

  1. IOS 线程的总结(及cell的图片下载)
  2. VC++ 禁止WebBrowser网页跳转时发出的声音和禁止网页上的文字被选择
  3. Shell 获取进程号
  4. WinAPI 字符及字符串函数(13): lstrcmp、lstrcmpi - 对比串
  5. 全国计算机报名入口攀枝花学院,2017年攀枝花学院艺术类专业考试网上报名入口...
  6. 拓端tecdat|R语言生态学建模:增强回归树(BRT)预测短鳍鳗生存分布和影响因素
  7. sklearn 决策树无法处理类别特征
  8. 深度学习-扩展数据集
  9. Android入门笔记07
  10. 【标注图像】windows下使用labelImg