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