Java线程安全 关于原子性与volatile的试验

1. 变量递增试验

 1     static /*volatile*/ int shared=0;//volatile也无法保证++操作的原子性
 2     static synchronized int incrShared(){//不加synchronized的话,shared最终结果值小于预期
 3         return ++shared;
 4     }
 5     public static void testIncrShared(String[] args) throws InterruptedException {
 6         shared=0;
 7         Thread[] thrds = new Thread[20];
 8         for(int j=0;j<thrds.length;j++){
 9             thrds[j] = new Thread(new Runnable() {
10                 @Override
11                 public void run() {
12                     for(int k=0;k<1000;k++){
13                         System.out.println(incrShared());
14                     }
15                 }
16             });
17         }
18         for(int j=0;j<thrds.length;j++){
19             thrds[j].start();
20         }
21         for(int j=0;j<thrds.length;j++){
22             thrds[j].join();
23         }
24         System.out.println(shared);
25     }

2. volatile试验

 1     static /*volatile*/ int a0,a1;//这里加volatile的话,可以避免r0==r1==0的结果
 2     static /*volatile*/ int r0,r1;//这里即使加volatile,也无法避免r0==r1==0的结果
 3     public static void testVolatile(String[] args) throws InterruptedException {
 4         int[] a=new int[2];
 5         int[] r=new int[2];
 6         final int SLEEP=10;
 7         final Object lock=new Object();
 8         Runnable run1=new Runnable() {
 9             @Override
10             public void run() {
11                 try {
12                     Thread.sleep(SLEEP);
13                 } catch (InterruptedException e) {
14                     e.printStackTrace();
15                 }
16                 //synchronized (lock) {//加锁也可以建立happens-before关系,避免r0==r1==0的结果
17                     a0=1;
18                 //}
19                 r1=a1;
20             }
21         };
22         Runnable run2=new Runnable() {
23             @Override
24             public void run() {
25                 try {
26                     Thread.sleep(SLEEP);
27                 } catch (InterruptedException e) {
28                     e.printStackTrace();
29                 }
30                 //synchronized (lock) {
31                     a1=1;
32                 //}
33                 r0=a0;
34             }
35         };
36         Thread thrd1;
37         Thread thrd2;
38
39         int i;
40         int[][] acnt=new int[2][2];
41         int[][] rcnt=new int[2][2];
42         for(i=0;i<10000;i++){
43             a0=a1=0;
44             r0=r1=0;
45             thrd1 = new Thread(run1);
46             thrd2 = new Thread(run2);
47
48             thrd1.start();
49             thrd2.start();
50
51             thrd1.join();
52             thrd2.join();
53
54             a[0]=a0;
55             a[1]=a1;
56             r[0]=r0;
57             r[1]=r1;
58             System.out.println(i);
59             System.out.println(Arrays.toString(a));
60             System.out.println(Arrays.toString(r));
61             acnt[a[0]][a[1]]++;
62             rcnt[r[0]][r[1]]++;
63         }
64         System.out.println(Arrays.deepToString(acnt));
65         System.out.println(Arrays.deepToString(rcnt));
66     }

3. volatile试验2

 1     static boolean shouldStop=false;
 2     public static void testVolatile2(String[] args) throws InterruptedException {
 3         shouldStop=false;
 4         Runnable run1=new Runnable() {
 5             @Override
 6             public void run() {
 7                 int i=0;
 8                 while (!shouldStop) {//无法读取到线程2修改后的shouldStop值,导致无限循环
 9                     i++;
10                     //System.out.println(i);//如果调用其他函数的话,就又可以读取到shouldStop的最新值了
11                 }
12             }
13         };
14         Runnable run2=new Runnable() {
15             @Override
16             public void run() {
17                 try {
18                     Thread.sleep(10);
19                 } catch (InterruptedException e) {
20                     e.printStackTrace();
21                 }
22                 shouldStop=true;
23             }
24         };
25         Thread thrd1;
26         Thread thrd2;
27
28         int i;
29         int[][] acnt=new int[2][2];
30         int[][] rcnt=new int[2][2];
31         for(i=0;i<100;i++){
32             thrd1 = new Thread(run1);
33             thrd2 = new Thread(run2);
34
35             thrd1.start();
36             thrd2.start();
37
38             thrd2.join();
39             System.out.println(i);
40             System.out.println(shouldStop);
41             thrd1.join();
42
43         }
44     }
时间: 2024-08-02 16:35:13

Java线程安全 关于原子性与volatile的试验的相关文章

Java线程工作内存与主内存变量交换过程及volatile关键字理解

Java线程工作内存与主内存变量交换过程及volatile关键字理解 1. Java内存模型规定在多线程情况下,线程操作主内存变量,需要通过线程独有的工作内存拷贝主内存变量副本来进行.此处的所谓内存模型要区别于通常所说的虚拟机堆模型: 2. 线程独有的工作内存和进程内存(主内存)之间通过8中原子操作来实现,如下图所示: 原子操作的规则(部分): 1) read,load必须连续执行,但是不保证原子性. 2) store,write必须连续执行,但是不保证原子性. 3) 不能丢失变量最后一次ass

Java线程安全:可见性,原子性,有序性

Java线程安全 可见性,原子性,有序性 Java内存模型(JMM) Java内存模型(Java Memory Model)描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这样的底层细节. 所有的变量都存储在主内存中. 每个线程都有自己独立的工作内存,里面保持该线程使用到的变量副本. 线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主内存中进行读写. 不同线程之间无法直接访问其他线程工作内存的变量,所以线程间变量值的传递需要

Java线程(二):线程同步synchronized和volatile

上篇通过一个简单的例子说明了线程安全与不安全,在例子中不安全的情况下输出的结果恰好是逐个递增的(其实是巧合,多运行几次,会产生不同的输出结果),为什么会产生这样的结果呢,因为建立的Count对象是线程共享的,一个线程改变了其成员变量num值,下一个线程正巧读到了修改后的num,所以会递增输出. 要说明线程同步问题首先要说明Java线程的两个特性,可见性和有序性.多个线程之间是不能直接传递数据交互的,它们之间的交互只能通过共享变量来实现.拿上篇博文中的例子来说明,在多个线程之间共享了Count类的

深入理解Java内存模型(四)——volatile

volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个锁对这些单个读/写操作做了同步.下面我们通过具体的示例来说明,请看下面的示例代码: class VolatileFeaturesExample { //使用volatile声明64位的long型变量 volatile long vl = 0L; public void set(long l) { vl = l;

Java线程使用大全

1.线程实现 1.Thread类 构造方法: 案例代码: public class Ex10_1_CaseThread extends Thread {// 创建一个类继承(extend)Thread类 String studentName; public Ex10_1_CaseThread(String studentName) {// 定义类的构造函数,传递参数 System.out.println(studentName + "申请访问服务器"); this.studentNam

Java - 线程基本概念

[java并发编程实战]-----线程基本概念 线程状态图 说明:线程共包括以下5种状态.1. 新建状态(New)         : 线程对象被创建后,就进入了新建状态.例如,Thread thread = new Thread().2. 就绪状态(Runnable): 也被称为"可执行状态".线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程.例如,thread.start().处于就绪状态的线程,随时可能被CPU调度执行.3. 运行状态(Running)

Java线程经典面试题

53道Java线程面试题 下面是Java线程相关的热门面试题,你可以用它来好好准备面试. 1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速.比如,如果一个线程完成一个任务要100毫秒,那么用十个线程完成改任务只需10毫秒.Java在语言层面对多线程提供了卓越的支持,它也是一个很好的卖点. 2) 线程和进程有什么区别? 线程是进程的子集,一个进程可以有很多线程,每条线程并

Java线程面试题 Top 50

原文链接: javarevisited 翻译: ImportNew.com- 李 广译文链接: http://www.importnew.com/12773.html 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员的欢迎.大多数待遇丰厚的Java开发职位都要求开发者精通多线程技术并且有丰富的Java程序开发.调试.优化经验,所以线程相关的问题在面试中经常会被提到. 在典型的Java面试中, 面试官会从线程

【转】Java线程面试题Top50

目录(?)[-] 50道Java线程面试题 1 什么是线程 2 线程和进程有什么区别 3 如何在Java中实现线程 4 用Runnable还是Thread 6 Thread 类中的start 和 run 方法有什么区别 7 Java中Runnable和Callable有什么不同 8 Java中CyclicBarrier 和 CountDownLatch有什么不同 9 Java内存模型是什么 10 Java中的volatile 变量是什么 11 什么是线程安全Vector是一个线程安全类吗 详见这