iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >深入探究Java线程不安全的原因与解决
  • 548
分享到

深入探究Java线程不安全的原因与解决

2024-04-02 19:04:59 548人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录一、什么是线程安全二、线程不安全的原因1、修改共享数据2、原子性3、内存可见性4、指令重排序三、解决线程安全方案一、什么是线程安全 想给出一个线程安全的确切定义是复杂的,但我们可

一、什么是线程安全

想给出一个线程安全的确切定义是复杂的,但我们可以这样认为:

如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的

二、线程不安全的原因

1、修改共享数据

static class Counter {
    public int count = 0;
    void increase() {
        count++;
    }
}
    public static void main(String[] args) throws InterruptedException {
        final Counter counter = new Counter();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                counter.increase();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                counter.increase();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(counter.count);
}

上面的线程不安全的代码中, 涉及到多个线程针对 counter.count 变量进行修改.此时这个 counter.count 是一个多个线程都能访问到的 “共享数据”

2、原子性

原子性就是 提供互斥访问,同一时刻只能有一个线程对数据进行操作,有时也把这个现象叫做同步互斥,表示操作是互相排斥的

不保证原子性会给多线程带来什么问题 如果一个线程正在对一个变量操作,中途其他线程插入进来了,如果这个操作被打断了,结果就可能是错误的。 这点也和线程的抢占式调度密切相关. 如果线程不是 “抢占” 的, 就算没有原子性, 也问题不大

3、内存可见性

可见性指, 一个线程对共享变量值的修改,能够及时地被其他线程看到.

Java 内存模型 (JMM): Java虚拟机规范中定义了Java内存模型. 目的是屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果.

   private static int count = 0;
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (count == 0) {
            }
            System.out.println(Thread.currentThread().getName() +
                    "执⾏完成");
        });
        t1.start();
        Scanner scanner = new Scanner(System.in);
        System.out.print("->");
        count = scanner.nextInt();
    }

4、指令重排序

一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)。

编译器对于指令重排序的前提

“保持逻辑不发生变化”. 这一点在单线程环境下比较容易判断, 但是在多线程环境下就没那么容易了, 多线程的代码执行复杂程度更高, 编译器很难在编译阶段对代码的执行效果进行预测, 因此激进的重排序很容易导致优化后的逻辑和之前不等价

三、解决线程安全方案

  • volatile解决内存可见性和指令重排序

代码在写入 volatile 修饰的变量的时候:

改变线程⼯作内存中volatile变量副本的值,将改变后的副本的值从⼯作内存刷新到主内存

  • 直接访问工作内存,速度快,但是可能出现数据不⼀致的情况
  • 加上 volatile , 强制读写内存. 速度是慢了, 但是数据变的更准确了

代码示例:


public class ThreadSeeVolatile {
    //全局变量
    private volatile static boolean flag = true;
    public static void main(String[] args) {
        //创建子线程
        Thread t1 = new Thread(() ->{
            System.out.println("1开始执行:" + LocalDateTime.now());
            while(flag){
            }
            System.out.println("2结束执行" + LocalDateTime.now());
        });
        t1.start();
        Thread t2 = new Thread(() ->{
            //休眠1s
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("修改flag=false"+ LocalDateTime.now());
            flag = false;
        });
        t2.start();
    }
}

volatile的缺点

volatile 虽然可以解决内存可见性和指令重排序的问题,但是解决不了原子性问题,因此对于 ++ 和 --操作的线程非安全问题依然解决不了

  • 通过synchronized实现原子性操作

jdk提供锁分两种:

①一种是synchronized,依赖JVM实现锁,因此在这个关键字作用对象的作用范围内是同一时刻只能有一个线程进行操作;

②另一种是LOCK,是JDK提供的代码层面的锁,依赖CPU指令,代表性的是ReentrantLock。

  • synchronized 会起到互斥效果, 某个线程执行到某个对象的synchronized 中时, 其他线程如果也执行到同一个对象 synchronized 就会阻塞等待.
  • 进入 synchronized 修饰的代码块, 相当于 加锁
  • 退出 synchronized 修饰的代码块, 相当于 解锁

synchronized修饰的对象有四种:

(1)修饰代码块,作用于调用的对象

(2)修饰方法,作用于调用的对象

(3)修饰静态方法,作用于所有对象

(4)修饰类,作用于所有对象

   // 修饰一个代码块: 明确指定锁哪个对象
    public void test1(int j) {
        synchronized (this) {
        }
    }
    // 修饰一个方法
    public synchronized void test2(int j) {
    }
    // 修饰一个类
    public static void test1(int j) {
        synchronized (SynchronizedExample2.class) {
        }
    }
    // 修饰一个静态方法
    public static synchronized void test2(int j) {
    }

到此这篇关于深入探究Java线程不安全的原因与解决的文章就介绍到这了,更多相关Java线程不安全内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 深入探究Java线程不安全的原因与解决

本文链接: http://www.lsjlt.com/news/147350.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 深入探究Java线程不安全的原因与解决
    目录一、什么是线程安全二、线程不安全的原因1、修改共享数据2、原子性3、内存可见性4、指令重排序三、解决线程安全方案一、什么是线程安全 想给出一个线程安全的确切定义是复杂的,但我们可...
    99+
    2024-04-02
  • 深入探究Java线程的状态与生命周期
    目录一、线程的状态新建(初始)就绪(可运行)运行阻塞死亡二、线程的状态转移三、线程的生命周期一、线程的状态 NEW: 安排了工作, 还未开始行动RUNNABLE: 可工作的. 又可...
    99+
    2024-04-02
  • 深入探究Java线程的创建与构造方法
    目录一、创建线程启动线程—start 方法方法一方法二方法三方法四方法五方法六二、run方法和start方法的区别①方法性质不同②执行速度不同③调用次数不同总结三、线程的...
    99+
    2024-04-02
  • 深入探究Java线程与进程有哪些区别
    目录一、进程线和程的概念二、为什么要有线程三、进程和线程的关系四、线程和进程的区别(重点)五、用户线程和守护线程区别一、进程线和程的概念 线程: 一个线程是一个独立的执行流,每个线程...
    99+
    2024-04-02
  • Java深入探索线程安全和线程通信的特性
    目录一、线程安全(重点)1、线程安全概念2、产生线程不安全的情况3、线程不安全的原因4、如何解决线程不安全问题二、synchronized关键字1、使用2、特性三、volatile关...
    99+
    2024-04-02
  • java线程不安全的原因是什么
    今天就跟大家聊聊有关java线程不安全的原因是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发;...
    99+
    2023-06-14
  • simpledateformat线程不安全的原因
    这篇文章将为大家详细讲解有关simpledateformat线程不安全的原因,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。原因:在多线程环境下,当多个线程同时使用相同的SimpleDateFormat对象...
    99+
    2023-06-15
  • 深入理解线程安全与Singleton
    线程安全是个非常棘手的问题。即使你合理的使用了锁(lock),依然可能不会产生预期的效果。让我们来看看貌似合理的代码复制代码 代码如下:X=0;Thread 1  ...
    99+
    2022-11-15
    线程安全 Singleton
  • Java并发编程:同步机制与线程安全探究
    在现代软件开发中,多线程编程已经成为了必不可少的一部分。在Java中,线程的使用非常方便,但是也带来了一些问题,比如线程安全问题。为了解决这些问题,Java提供了一些同步机制。在本文中,我们将探究Java中的同步机制和线程安全。 一、线程...
    99+
    2023-11-09
    同步 numy 日志
  • 深入探究一下Java中不同的线程间数据通信方式
    目录1、多线程如何共享数据2、子线程如何继承父线程数据3、相关问题1、多线程如何共享数据 多线程数据共享可以分为以下2种情况,线程实现代码相同及线程实现代码不同。 线程实现代码相同 ...
    99+
    2023-05-16
    Java线程数据通信方式 Java线程数据通信 Java线程通信 Java线程
  • 404错误的原因和解决方法的深入研究
    探究HTTP状态码404的原因和解决途径 引言:在浏览网页的过程中,我们经常会遇到HTTP状态码404。这个状态码表示服务器未能找到请求的资源。在本文中,我们将探究HTTP状态码404...
    99+
    2024-02-25
    http 状态码 原因 解决途径
  • PHP多线程难题:探索原因与解决方案
    PHP作为一种流行的服务器端脚本语言,广泛应用于Web开发领域。然而,PHP本身在处理多线程任务时存在一些难题,这些难题可能导致程序性能下降甚至出现意外情况。本文将探讨PHP多线程问题...
    99+
    2024-04-02
  • StringBuilder是线程不安全的原因是什么
    这篇文章主要介绍了StringBuilder是线程不安全的原因是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇StringBuilder是线程不安全的原因是什么文章都会有所收获,下面我们一起来看看吧。原因分...
    99+
    2023-06-27
  • 深入剖析 Java 线程池的原理与实践
    原理 线程池维护一个固定大小的线程池,这些线程处于空闲状态,等待处理任务。当一个任务提交给线程池时,它会分配一个空闲线程来执行它。如果所有线程都处于繁忙状态,则新任务将放入队列中等待执行。 线程池的常见参数包括: 核心线程数:线程池中最...
    99+
    2024-03-13
    线程池
  • Java线程之安全与不安全的示例分析
    这篇文章将为大家详细讲解有关Java线程之安全与不安全的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。当我们查看JDK API的时候,总会发现一些类说明写着,线程安全或者线程不安全,比如说Stri...
    99+
    2023-05-30
    java
  • Java SimpleDateFormat线程不安全问题怎么解决
    本篇内容主要讲解“Java SimpleDateFormat线程不安全问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java SimpleDateFormat线程...
    99+
    2023-07-05
  • java的SimpleDateFormat线程不安全的几种解决方案
    目录场景SimpleDateFormat线程为什么是线程不安全的呢?验证SimpleDateFormat线程不安全解决方案解决方案1:不要定义为static变量,使用局部变量解决方案...
    99+
    2024-04-02
  • 深入理解Java编程线程池的实现原理
    在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间...
    99+
    2023-05-30
    java 线程池 ava
  • 如何解决Java中SimpleDateFormat线程不安全的问题
    这篇文章将为大家详细讲解有关如何解决Java中SimpleDateFormat线程不安全的问题,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1.什么是线程不安全?线程不安全也叫非线程安全,是指多线程执行中...
    99+
    2023-06-15
  • 解决Java中SimpleDateFormat线程不安全的五种方案
    目录1.什么是线程不安全? 线程不安全的代码 2.解决方案 ① 将SimpleDateFormat变为局部变量 ② 使用synchronized加锁 ③ 使用Lock加锁 ④ 使用T...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作