ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线程安全性

2022-05-11 17:34:06  阅读:173  来源: 互联网

标签:java public num static countDownLatch 线程 安全性


  • 线程安全
当多个线程访问某个类,不管运行时环境采用何种调度方式或者这些线程如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类为线程安全的
  • 新建线程不安全操作的案例类
public class UnSafeThread {

    private static int num = 0;

    private static CountDownLatch countDownLatch = new CountDownLatch(10);

    /**
     * 每次调用对num进行++操作
     */
    public static void  inCreate() {
        num++;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                for (int j = 0; j < 100; j++) {
                    inCreate();
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //每个线程执行完成之后,调用countDownLatch
                countDownLatch.countDown();
            }).start();
        }

        while (true) {
            if (countDownLatch.getCount() == 0) {
                System.out.println(num);
                break;
            }
        }

    }
}
  • 打开cmd
# 编译
C:\work\git\spring_learn_repo\concurrent\src\main\java\com\xdclass\synopsis>javac -encoding UTF-8 UnsafeThread.java
# 反编译
C:\work\git\spring_learn_repo\concurrent\src\main\java\com\xdclass\synopsis>javap -c UnsafeThread.class
Compiled from "UnsafeThread.java"
public class com.xdclass.synopsis.UnSafeThread {
  public com.xdclass.synopsis.UnSafeThread();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void inCreate();
    Code:
       0: getstatic     #2                  // Field num:I
       3: iconst_1
       4: iadd
       5: putstatic     #2                  // Field num:I
       8: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: bipush        10
       5: if_icmpge     29
       8: new           #3                  // class java/lang/Thread
      11: dup
      12: invokedynamic #4,  0              // InvokeDynamic #0:run:()Ljava/lang/Runnable;
      17: invokespecial #5                  // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
      20: invokevirtual #6                  // Method java/lang/Thread.start:()V
      23: iinc          1, 1
      26: goto          2
      29: getstatic     #7                  // Field countDownLatch:Ljava/util/concurrent/CountDownLatch;
      32: invokevirtual #8                  // Method java/util/concurrent/CountDownLatch.getCount:()J
      35: lconst_0
      36: lcmp
      37: ifne          29
      40: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      43: getstatic     #2                  // Field num:I
      46: invokevirtual #10                 // Method java/io/PrintStream.println:(I)V
      49: goto          52
      52: return

  static {};
    Code:
       0: iconst_0
       1: putstatic     #2                  // Field num:I
       4: new           #18                 // class java/util/concurrent/CountDownLatch
       7: dup
       8: bipush        10
      10: invokespecial #19                 // Method java/util/concurrent/CountDownLatch."<init>":(I)V
      13: putstatic     #7                  // Field countDownLatch:Ljava/util/concurrent/CountDownLatch;
      16: return
}
  • 结论
       0: getstatic     #2                  // Field num:I    获取指定类的静态域,并将其押入栈顶 
       3: iconst_1                                            将int型1押入栈顶
       4: iadd                                                将栈顶两个int型
相加,将结果押入栈顶
       5: putstatic     #2                  // Field num:I    为指定类静态域赋值
       8: return
  • 步骤
1、获取静态域num = 0
2、第1个线程对num加1
3、若这时创建第2个线程,对num加1
4、最后的预期结果应该为2,实际结果为1

# 产生线程不安全问题的原因:num++ 不是原子性操作,被拆分成好几个步骤,在多线程并发执行的情况下,因为cpu调度,多线程快递切换,有可能两个同一时刻都读取了同一个num值,之后对它进行+1操作,导致线程安全性

  • 原子性操作
一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行
  • 将非原子性操作变成原子性
使用synchronize关机字,使得操作具有原子性

volatile关键字仅仅保证可见性,并不保证原子性 
  • 代码案例
public class UnSafeThread {

    private static int num = 0;

    private static CountDownLatch countDownLatch = new CountDownLatch(10);

    /**
     * 每次调用对num进行++操作
     */
    public static synchronized void  inCreate() {
        num++;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                for (int j = 0; j < 100; j++) {
                    inCreate();
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //每个线程执行完成之后,调用countDownLatch
                countDownLatch.countDown();
            }).start();
        }

        while (true) {
            if (countDownLatch.getCount() == 0) {
                System.out.println(num);
                break;
            }
        }

    }
}

标签:java,public,num,static,countDownLatch,线程,安全性
来源: https://www.cnblogs.com/chniny/p/16258845.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有