其他分享
首页 > 其他分享> > 线程安全性

线程安全性

作者:互联网

当多个线程访问某个类,不管运行时环境采用何种调度方式或者这些线程如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类为线程安全的
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;
            }
        }

    }
}
# 编译
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