线程安全性

定义:当多个线程访问某个类时,不管运行时以何种方式调度或者这些进程如何交替执行,在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的

原子性

 1 package com.mmall.concurrency.demo.atomic;
 2 
 3 import com.mmall.concurrency.annoations.ThreadSafe;
 4 
 5 import java.util.concurrent.CountDownLatch;
 6 import java.util.concurrent.ExecutorService;
 7 import java.util.concurrent.Executors;
 8 import java.util.concurrent.Semaphore;
 9 import java.util.concurrent.atomic.AtomicLong;
10 
11 @ThreadSafe
12 public class AtomicDemo1 {
13     public static int clientTotal = 5000;
14     public static int threadTotal = 200;
15     public static AtomicLong count = new AtomicLong(0);
16 
17     public static void main(String[] args) throws Exception {
18         ExecutorService executorService = Executors.newCachedThreadPool();
19         final Semaphore semaphore = new Semaphore(threadTotal);
20         final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
21         for (int i = 0; i < clientTotal ; i++) {
22             executorService.execute(() -> {
23                 try {
24                     semaphore.acquire();
25                     add();
26                     semaphore.release();
27                 } catch (Exception e) {
28                     e.printStackTrace();
29                 }
30                 countDownLatch.countDown();
31             });
32         }
33         countDownLatch.await();
34         executorService.shutdown();
35         System.out.println("count:"+count.get());
36     }
37 
38     private static void add() {
39         count.incrementAndGet();
40     }
41 }
42 /*
43 public final long incrementAndGet() {
44     return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L;
45 }
46 
47 public final long getAndAddLong(Object var1, long var2, long var4) {
48     long var6;
49     do {
50         var6 = this.getLongVolatile(var1, var2);
51     } while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));
52 
53     return var6;
54 }
55  */
 1 package com.mmall.concurrency.demo.atomic;
 2 
 3 import com.mmall.concurrency.annoations.ThreadSafe;
 4 
 5 import java.util.concurrent.CountDownLatch;
 6 import java.util.concurrent.ExecutorService;
 7 import java.util.concurrent.Executors;
 8 import java.util.concurrent.Semaphore;
 9 import java.util.concurrent.atomic.LongAdder;
10 
11 @ThreadSafe
12 public class AtomicDemo2 {
13     public static int clientTotal = 5000;
14     public static int threadTotal = 200;
15     public static LongAdder count = new LongAdder();
16 
17     public static void main(String[] args) throws Exception {
18         ExecutorService executorService = Executors.newCachedThreadPool();
19         final Semaphore semaphore = new Semaphore(threadTotal);
20         final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
21         for (int i = 0; i < clientTotal ; i++) {
22             executorService.execute(() -> {
23                 try {
24                     semaphore.acquire();
25                     add();
26                     semaphore.release();
27                 } catch (Exception e) {
28                     e.printStackTrace();
29                 }
30                 countDownLatch.countDown();
31             });
32         }
33         countDownLatch.await();
34         executorService.shutdown();
35         System.out.println("count:"+count);
36     }
37 
38     private static void add() {
39         count.increment();
40     }
41 }
 1 package com.mmall.concurrency.demo.atomic;
 2 
 3 import com.mmall.concurrency.annoations.ThreadSafe;
 4 
 5 import java.util.concurrent.atomic.AtomicReference;
 6 
 7 @ThreadSafe
 8 public class AtomicDemo3 {
 9     private static AtomicReference<Integer> count = new AtomicReference<>(0);
10     public static void main(String[] args) {
11         count.compareAndSet(0, 2); // 2
12         count.compareAndSet(0, 1); // no
13         count.compareAndSet(1, 3); // no
14         count.compareAndSet(2, 4); // 4
15         count.compareAndSet(3, 5); // no
16         System.out.println("count:"+count.get());
17     }
18 }
19 /*
20 count:4
21  */
 1 package com.mmall.concurrency.demo.atomic;
 2 
 3 import com.mmall.concurrency.annoations.ThreadSafe;
 4 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
 5 
 6 @ThreadSafe
 7 public class AtomicDemo4 {
 8     private static AtomicIntegerFieldUpdater<AtomicDemo4> updater =
 9             AtomicIntegerFieldUpdater.newUpdater(AtomicDemo4.class, "count");
10     public volatile int count = 100;
11 
12     public int getCount() {
13         return count;
14     }
15 
16     public static void main(String[] args) {
17         AtomicDemo4 demo4 = new AtomicDemo4();
18         if (updater.compareAndSet(demo4, 100, 120))
19             System.out.println("update success "+demo4.getCount());
20 
21         if (updater.compareAndSet(demo4, 100, 120))
22             System.out.println("update success "+demo4.getCount());
23         else
24             System.out.println("update failed "+demo4.getCount());
25     }
26 }
27 /*
28 update success 120
29 update failed 120
30  */
 1 package com.mmall.concurrency.demo.atomic;
 2 
 3 import com.mmall.concurrency.annoations.ThreadSafe;
 4 
 5 import java.util.concurrent.CountDownLatch;
 6 import java.util.concurrent.ExecutorService;
 7 import java.util.concurrent.Executors;
 8 import java.util.concurrent.Semaphore;
 9 import java.util.concurrent.atomic.AtomicBoolean;
10 
11 @ThreadSafe
12 public class AtomicDemo5 {
13     private static AtomicBoolean isHappened = new AtomicBoolean(false);
14     public static int clientTotal = 5000;
15     public static int threadTotal = 200;
16 
17     public static void main(String[] args) throws Exception {
18         ExecutorService executorService = Executors.newCachedThreadPool();
19         final Semaphore semaphore = new Semaphore(threadTotal);
20         final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
21         for (int i = 0; i < clientTotal ; i++) {
22             executorService.execute(() -> {
23                 try {
24                     semaphore.acquire();
25                     test();
26                     semaphore.release();
27                 } catch (Exception e) {
28                     e.printStackTrace();
29                 }
30                 countDownLatch.countDown();
31             });
32         }
33         countDownLatch.await();
34         executorService.shutdown();
35         System.out.println("isHappened:"+isHappened.get());
36     }
37 
38     private static void test() {
39         if (isHappened.compareAndSet(false, true)) {
40             System.out.println("execute");
41         }
42     }
43 }
44 /*
45 execute
46 isHappened:true
47  */
 1 package com.mmall.concurrency.demo.sync;
 2 
 3 import java.util.concurrent.ExecutorService;
 4 import java.util.concurrent.Executors;
 5 
 6 public class SynchronizedDemo1 {
 7     public void fun1(int j) {
 8         synchronized (this) {
 9             for (int i = 0; i < 10; i++) {
10                 System.out.println("fun1:"+j+" "+i);
11             }
12         }
13     }
14 
15     public synchronized void fun2(int j) {
16         for (int i = 0; i < 10; i++) {
17             System.out.println("fun2:"+j+" "+i);
18         }
19     }
20 
21     public static void main(String[] args) {
22         SynchronizedDemo1 s1 = new SynchronizedDemo1();
23         SynchronizedDemo1 s2 = new SynchronizedDemo1();
24         ExecutorService executorService = Executors.newCachedThreadPool();
25         executorService.execute(() -> {
26             s1.fun2(1);
27         });
28         executorService.execute(() -> {
29             s2.fun2(2);
30         });
31     }
32 }
33 /*
34 fun2:1 0
35 fun2:1 1
36 fun2:2 0
37 fun2:2 1
38 fun2:2 2
39 fun2:2 3
40 fun2:2 4
41 fun2:2 5
42 fun2:2 6
43 fun2:1 2
44 fun2:2 7
45 fun2:1 3
46 fun2:1 4
47 fun2:1 5
48 fun2:1 6
49 fun2:1 7
50 fun2:1 8
51 fun2:2 8
52 fun2:1 9
53 fun2:2 9
54  */
 1 package com.mmall.concurrency.demo.sync;
 2 
 3 import java.util.concurrent.ExecutorService;
 4 import java.util.concurrent.Executors;
 5 
 6 public class SynchronizedDemo2 {
 7     public static void fun1(int j) {
 8         synchronized (SynchronizedDemo2.class) {
 9             for (int i = 0; i < 10; i++) {
10                 System.out.println("fun1:"+j+" "+i);
11             }
12         }
13     }
14 
15     public static synchronized void fun2(int j) {
16         for (int i = 0; i < 10; i++) {
17             System.out.println("fun2:"+j+" "+i);
18         }
19     }
20 
21     public static void main(String[] args) {
22         SynchronizedDemo2 s1 = new SynchronizedDemo2();
23         SynchronizedDemo2 s2 = new SynchronizedDemo2();
24         ExecutorService executorService = Executors.newCachedThreadPool();
25         executorService.execute(() -> {
26             s1.fun2(1);
27         });
28         executorService.execute(() -> {
29             s2.fun2(2);
30         });
31     }
32 }
33 /*
34 fun2:1 0
35 fun2:1 1
36 fun2:1 2
37 fun2:1 3
38 fun2:1 4
39 fun2:1 5
40 fun2:1 6
41 fun2:1 7
42 fun2:1 8
43 fun2:1 9
44 fun2:2 0
45 fun2:2 1
46 fun2:2 2
47 fun2:2 3
48 fun2:2 4
49 fun2:2 5
50 fun2:2 6
51 fun2:2 7
52 fun2:2 8
53 fun2:2 9
54  */

synchronized:不可中断锁,适合竞争不激烈,可读性好

Lock:可中断锁,多样化同步,竞争激烈时能维持常态

Atomic:竞争激烈时能维持常态,比Lock性能好,但只能同步一个值

可见性

导致共享变量在线程间不可见的原因:

1. 线程交叉执行

2. 重排序结合线程交叉执行

3. 共享变量更新后的值没有在工作内存与主内存间及时更新

 

JVM关于synchronized的两条规定:

1. 线程解锁前,必须把共享变量的最新值刷新到主内存

2. 线程加锁时,会清空工作内存中共享变量的值,从主内存中重新读取需要的最新值(注意,加锁与解锁是同一把锁)

 

volatile通过加入内存屏障和禁止重排序优化来实现可见性

1. 对volatile变量写操作时,会在写操作后加入一条store屏障指令,把本地内存中的共享变量值刷新到主内存

2. 对volatile变量读操作时,会在读操作前加入一条load屏障指令,从主内存中读取共享变量

volatile只能保证可见性,并不能保证线程安全

volatile适合作为状态标记量

 1 volatile boolean inited=false;
 2 
 3 //线程1
 4 context=loadContext();
 5 inited=true;
 6 
 7 //线程2
 8 while(!inited){
 9     sleep();
10 }
11 doSomethingWithConfig(context);

有序性

happens-before原则

见深入理解Java虚拟机P376

posted @ 2018-04-08 20:22  sakura1027  阅读(113)  评论(0编辑  收藏  举报