首页 > 编程语言 >JAVA多线程-如何保证线程安全

JAVA多线程-如何保证线程安全

时间:2024-09-10 14:54:15浏览次数:12  
标签:main JAVA Main2 修改 线程 static 多线程 public

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

如何保证线程安全

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

线程同步

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

可见性

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

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

有序性

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

原子性

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

具体方法

volatile 关键字

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

保证可见性

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

不加 volatile 关键字

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 关键字

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给指令的前后加上内存屏障,屏障两边的指令不可以重排序,保证有序。

例子 单例模式

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

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);  // true
    System.out.println(m1 == m3);  // true
    System.out.println(m2 == m3);  // true
}

}

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

synchronized关键字

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

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

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

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

防止死锁

原因

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

后果

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

检查死锁

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

解决方法

资源一次性分配

当线程满足条件时释放自己已占有的资源

资源有序分配

标签:main,JAVA,Main2,修改,线程,static,多线程,public
From: https://blog.51cto.com/u_16780696/11971589

相关文章

  • Java面试题大总结(全网最全)
    1、普通类和抽象类有哪些区别?抽象类不能被实例化;抽象类可以有抽象方法,只需申明,无须实现;有抽象方法的类一定是抽象类;抽象类的子类必须实现抽象类中的所有抽象方法,否则子类仍然是抽象类;抽象方法不能声明为静态、不能被static、final修饰。2、接口和抽象类有什么区别?(1)接口......
  • java多线程转换文件格式
    privatestaticfinalintTHREAD_COUNT=4;//线程数privatestaticfinalintBUFFER_SIZE=1024;//缓冲区大小/***多线程读取文件,转换文件编码格式4线程1Mb缓存**@paraminputFile输入文件Stringinput="E:/02code/web/test.txt"......
  • 常见的Java课程设计/毕业设计选题
    从网上整理收集了常见的java系统设计源码,可以用于课程作业或者毕业设计。技术栈:java/springboot/mysql/js/vue1.基于java的家政预约网站系统平台采用B/S结构,后端采用主流的Springboot框架进行开发,前端采用主流的Vue.js进行开发。整个平台包括前台和后台两个部分。前台功能包括:首页......
  • 最全Java面试八股文过过过
    1.Java创建对象得五种方式?(1)new关键字  (2)Class.newInstance (3)Constructor.newInstance(4)Clone方法  (5)反序列化2.想要线程安全的HashMap怎么办?(1)使用ConcurrentHashMap(2)使用HashTable(3)Collections.synchronizedHashMap()方法3.ConcurrentHashMap原如何保......
  • Java学习 - 多线程第二部分
    1.线程池1.1线程状态介绍当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。线程对象在不同的时期有不同的状态。那么Java中的线程存在哪几种状态呢?Java中的线程状态被定义在了java.lang.Thread.State枚举类中,State枚举类的源码如下:publi......
  • Java学习 - 反射&动态代理
    马上就要把Java的基础部分更新完了,后面会更新一些别的内容,也会多学习一些别的东西提升一下自己。加油加油加油!1.反射1.1反射的概述:**专业的解释(了解一下):**是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意......
  • Java学习 - 网络编程
    1.网络编程入门1.1网络编程概述计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统网络编程在网络通信协议下,不同计算机上运行的程序......
  • java+vue计算机毕设车票订购系统【源码+开题+论文+程序】
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和人们生活节奏的加快,传统的车票购买方式已难以满足日益增长的出行需求。传统的售票窗口排队购票不仅耗时耗力,还常常因信息不......
  • java+vue计算机毕设车票管理系统【源码+开题+论文+程序】
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着交通网络的日益发达和人们出行需求的不断增长,车票管理系统在现代社会中扮演着至关重要的角色。传统的车票购买方式往往存在排队时间长、信息不透......
  • java+vue计算机毕设出版社高校教材样书管理【源码+开题+论文+程序】
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着高等教育的快速发展与课程体系的不断革新,高校教材作为知识传播的重要载体,其更新换代的速度日益加快。出版社作为教材的主要供给方,面临着如何高效......