目录

  • 多线程——保证线程安全
    • 含义
    • 如何保证线程安全
    • 具体方法
      • volatile关键字
        • 保证可见性
        • 禁止重排序
      • synchronized关键字
        • 保证原子性
      • 防止死锁
        • 原因
        • 后果
        • 检查死锁
        • 解决方法

不积跬步,无以至千里;不积小流,无以成江海。要沉下心来,诗和远方的路费真的很贵!

多线程——保证线程安全

含义

线程安全:指在多线程对一个共享资源同时进行操作的时候,所得到的结果每次都是一样的。

如何保证线程安全

方法:要保证线程安全,就必须保证线程同步。保证线程的可见性有序性原子性

  • 线程同步

线程同步的含义和字面意义相反。同步其实是线程“排队”的意思。就是让线程按照一定的顺序执行,每一时刻,只有一个线程,对共享资源进行操作。

  • 可见性

一个线程对共享资源的操作,所有的线程都可以看见。

以具体实例来说明。就好比一个线程修改了一个数据,其他线程立马知道该数据被修改了。即就是在线程和主存之间有一个缓存,线程修改数据,是在缓存中修改,还需要在主存修改,而可见性就是立刻在主存中修改,防止其他线程读取时,发生数据错误。

  • 有序性

就是代码的执行顺序是有序的,执行的顺序不会发生改变。

  • 原子性

顾名思义,原子是一个不可分的整体。就是一个代码块,要么全部执行,要么全部不执行,只要其执行了,就无法被任何事务打断。

具体方法

volatile关键字

作用:保证线程可见性和禁止指令重排序。

保证可见性

实现原理:当一个变量被volatile修饰,一旦其发生改变,那么根据缓存一致性协议,其他线程的缓存都会失效,需要重新从内存中获取数据,就可以保证数据的准确性。就好比这个数据修改了,其他线程缓存失效,就知道了它被修改了,就要重新获取,即可见的含义。

不加volatile关键字

package com.hnu;public class Main2 {// static 静态变量 全局private static boolean flag = false;public static void main(String[] args) throws InterruptedException {new Thread(new Runnable() {//未停止,不知道已修改public void run() {while(true) {if(flag) {break;}}System.out.println("变量变化");};}).start();//主线程修改flag值Thread.sleep(1000);flag = true;}
}

线程先启动,启动后修改变量,未加关键字修饰,子线程不知道其变量值已经发生变化,即不可见,所以死循环无法停止。

加volatile关键字

package com.hnu;public class Main2 {// static 静态变量 全局private static volatile boolean flag = false;public static void main(String[] args) throws InterruptedException {new Thread(new Runnable() {//停止,知道已修改public void run() {while(true) {if(flag) {break;}}System.out.println("变量变化");};}).start();//主线程修改flag值Thread.sleep(1000);flag = true;}
}

加入关键字,首先先死循环,然后修改其值,知道其修改完成,然后调用,停止死循环,输出文字。可以证明其保证了可见性。

禁止重排序

实现原理:通过jvm给指令的前后加上内存屏障,屏障两边的指令不可以重排序,保证有序。

例子:单例模式

禁止重排序的经典案例就是单例模式的创建过程中的双重检测锁。

package com.hnu;public class Main2 {//自己对象,禁止重排序private volatile static Main2 main = null;//构造方法private Main2() {}//创建自己public static Main2 getInstance() {if(main == null) {//类锁,双重检测锁synchronized(Main2.class) {if(main == null) {main = new Main2();}}}return main;}public static void main(String[] args) {Main2 m1 = getInstance();Main2 m2 = getInstance();Main2 m3 = getInstance();System.out.println(m1 == m2);System.out.println(m1 == m3);System.out.println(m2 == m3);}
}

可知三个对象,都是同一个对象,内存地址相同。

synchronized关键字

作用:利用线程互斥来实现线程同步,即通过同一时刻只有一个线程可以访问(互斥),来实现线程的原子性,全部执行完,才能换线程执行,线程顺序执行(同步)。

synchronized最主要的就是保持原子性,保持原子性,最主要的就是线程同步,同步最基本的方法就是加锁,加锁最直接的就是加synchronized关键字

效率:synchronized在早期是一把重量级锁,但是随着java发展,如今的效率已经很高。例如i++不是原子操作,它分为三步:1.获取i的值 2.修改i的值 3.将修改的值赋予i 。如果在其外面加入synchronized关键字,保证了每次只有一个线程可以修改i,那么就保证了i++在并发环境下的安全性。

保证原子性

上面的双重检测锁也使用了synchronized关键字,加同一个锁的线程同步互斥,里面的代码块在同一时刻,只有一个线程可以访问,所以保证了唯一实例。

防止死锁

原因

两个线程相互请求对方持有的资源,都不释放自己持有的资源,相互阻塞,导致死锁。

后果

至少有两个线程相互阻塞等待对方的资源。

检查死锁

使用jdk工具jconsole查看线程的状态。

解决方法

  1. 资源一次性分配
  2. 当线程满足条件时释放自己已占有的资源
  3. 资源有序分配

多线程——保证线程安全相关推荐

  1. 多线程下C#如何保证线程安全?

    多线程编程相对于单线程会出现一个特有的问题,就是线程安全的问题.所谓的线程安全,就是如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是 ...

  2. 按照顺序执行_问一个多线程的问题:如何才能保证线程有序执行?

    面试的时候你是否经常被问到这样的问题: 你一般通过什么方式去控制线程的执行顺序? 碰到这样的问题,我的内心其实是很抵触的! 开什么玩笑?我怎么会控制它呢?我为什么要控制它? 其实不用慌,这个问题并不难 ...

  3. 多线程情况下如何保证线程安全

    一.线程安全等级 其实线程安全并不是一个"非黑即白"单项选择题.按照"线程安全"的安全程度由强到弱来排序,我们可以将java语言中各种操作共享的数据分为以下5类 ...

  4. MFC 多线程及线程同步

    一.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消息机制,通常 ...

  5. 它又来了!C**HashMap是如何保证线程安全的?会用不就完了?

    欢迎关注方志朋的博客,回复"666"获面试宝典 阅读此篇文章,你需要有以下知识基础 Java内存模型,可见性问题 CAS HashMap底层原理 我们知道,在日常开发中使用的Has ...

  6. Java并发编程 synchronized保证线程安全的原理

    文章转载致博客 blog.csdn.net/javazejian/- 自己稍加完善. 线程安全是并发编程中的重要关注点,应该注意到的是,造成线程安全问题的主要诱因有两点,一是存在共享数据(也称临界资源 ...

  7. java同步锁售票_Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)...

    学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是 ...

  8. 多线程:线程安全?如何实现?

    多个线程不管以何种方式访问某个类,并且在主调代码中不需要进行同步,都能表现正确的行为. 线程安全有以下几种实现方式: 1)不可变 为什么是不可变? 不可变(Immutable)的对象一定是线程安全的, ...

  9. Java多线程02(线程安全、线程同步、等待唤醒机制)

    Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...

  10. 多线程 空值线程数_【开发者成长】深入理解多线程编程

    云栖号资讯:[点击查看更多行业资讯] 在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 为什么要使用多线程? 防止并发编程出错最好的办法就是不写并发程序 既然多线程编程容易出错,为什么它 ...

最新文章

  1. 符合标准的TreeView实现(Div+CSS+JS+ASP.NET)
  2. java_ant详解
  3. html语言的空格键,如何在如何在HTML中插入空格中插入空格
  4. python3爬虫实例-Python3 爬虫实例(一)-- 简单网页抓取
  5. java流的序列化_Java中的对象流和序列化介绍
  6. sqlite3数据库使用
  7. 两个文件比较 linux,linux下比较2个文件
  8. BrightHouse存储引擎
  9. C++调用C#编写的DLL【转】
  10. java+widthstep_关于IplImage中widthstep的大小与width,nchannels等的关系的问题
  11. 基于steamworks获取steam用户头像
  12. 小赛毛游C记——初识C语言(1)
  13. 华硕路由器流量管理QoS设置
  14. stm32:时钟系统
  15. 如何在电脑上安装虚拟机和系统。全网最全教程,不接受反驳。
  16. 离散数学中的x|y是什么意思?
  17. 【译】 SafetyNet: Google's tamper detection - Part 2
  18. Android logo图标的尺寸
  19. Xftp的介绍及下载安装教程
  20. Ubuntu下安装微信(非网页版)、TIM、QQ

热门文章

  1. 基于CC2430的基础实验5---时钟模式
  2. caj文档如何免费转换成pdf格式
  3. SQL Server 2005“错误1706。安装程序找不到需要的文件。请检查……”的处理办法
  4. Select at least one project的解决方法
  5. SharePoint CAML 查询时间类型
  6. Excel如何将一列数据转为一行?
  7. 秀米svg点击显示另一张图_时隔五年再用秀米,我发现了这个超强玩法
  8. 为什么公司宁愿花15k去重招一个应届生,也不愿意加薪5k留住老程序员?
  9. ACM常用数据结构小结与实现
  10. Java基础----交通工具的继承写法(面向对象的三大特征)