什么是线程安全性?如何线程安全
Posted jtrun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么是线程安全性?如何线程安全相关的知识,希望对你有一定的参考价值。
什么是线程安全?
--当多个线程访问某个类时,不管运行环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的协同或者同步,这个类都能表现出正确的行为,那么这个类是线程安全的。
1.原子性(Aumic包)
AutomicXXX类 :采用CAS机,即 unsafe.compare.AndSwapInt
public class AtomicControllerTest public static int clientTotal = 5000; //请求总数 public static int threadTotal = 200; //同时并发的线程数 public static AtomicInteger count = new AtomicInteger(0); public static void main(String[] args) throws Exception ExecutorService executorService = Executors.newCachedThreadPool(); //创建线程池 final Semaphore semaphore = new Semaphore(threadTotal); //信号量(线程数) final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); //计数器 (把请求计数) for(int i =0 ; i < clientTotal ; i++) executorService.execute(()-> try semaphore.acquire();//信号量 判断进程是否执行 add(); semaphore.release(); catch (Exception e) log.error("Exception:", e); countDownLatch.countDown(); ); countDownLatch.await(); //当所有请求结束 executorService.shutdown(); log.info("count:", count); private static void add() count.incrementAndGet();
上面的代码是线程安全的,要是将AutomicInteger换成Integer,add方法也随着变成count++,线程将是不安全的。
incrementAndGet中的getAndAddInt是最为关键的代码。
var1 是传进来的对象(count), 如果执行3+1操作,var2是当前的值3,var 4 是1
var5 是底层的值,也就是从主内存拿到的值,由于其他线程也在进行操作,工作内存一直想主内存进行存取操作,主内存的值一直在变化
CAS操作的核心也就是保证从主内存拿到的值,是预期获得的值并没有被其他线程更改,所以在上面的方法中,一直在进行while操作,比较var2 和 var 5,
一旦相同,才会进行相加的操作。主内存和工作内存的运行图如下:
synchronized:
1.修饰方法和修饰一个类时,效果一致,先获得资源的线程,先运行,其余访问改资源的线程需要等待
package com.justrun.threadthink.sync; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @Slf4j public class SynchronizedExample2 // 修饰一个类 public static void test1(int j) synchronized (SynchronizedExample2.class) for (int i = 0; i < 10; i++) log.info("test1 - ", j, i); // 修饰一个静态方法 public static synchronized void test2(int j) for (int i = 0; i < 10; i++) log.info("test2 - ", j, i); public static void main(String[] args) SynchronizedExample2 example1 = new SynchronizedExample2(); SynchronizedExample2 example2 = new SynchronizedExample2(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() -> example1.test2(1); ); executorService.execute(() -> example2.test2(2); );
11:42:20.273 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 1 - 0
11:42:20.298 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 1 - 1
11:42:20.298 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 1 - 2
11:42:20.298 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 1 - 3
11:42:20.298 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 1 - 4
11:42:20.298 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 1 - 5
11:42:20.298 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 1 - 6
11:42:20.298 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 1 - 7
11:42:20.298 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 1 - 8
11:42:20.298 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 1 - 9
11:42:20.298 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 2 - 0
11:42:20.298 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 2 - 1
11:42:20.298 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 2 - 2
11:42:20.299 [pool-1-thread-2] INFO com.justrun.threadthink.syn
package com.justrun.threadthink.sync; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @Slf4j public class SynchronizedExample1 // 修饰一个代码块 public void test1(int j) synchronized (this) for (int i = 0; i < 10; i++) log.info("test1 - ", j, i); log.info("test-----", j); // 修饰一个方法 public synchronized void test2(int j) for (int i = 0; i < 10; i++) log.info("test2 - ", j, i); public static void main(String[] args) SynchronizedExample1 example1 = new SynchronizedExample1(); SynchronizedExample1 example2 = new SynchronizedExample1(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() -> example1.test1(1); ); executorService.execute(() -> example2.test1(2); );
c.SynchronizedExample2 - test2 2 - 3
11:42:20.299 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 2 - 4
11:42:20.299 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 2 - 5
11:42:20.299 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 2 - 6
11:42:20.299 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 2 - 7
11:42:20.299 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 2 - 8
11:42:20.299 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample2 - test2 2 - 9
Process finished with exit code 0
2。syhcnhronized修饰一个代码块和修饰一个方法,其原理大致一致,如果代码块修饰的整个方法的内容,那它们是一致的
随机调度资源,每个线程都有机会得到资源
package com.justrun.threadthink.sync; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @Slf4j public class SynchronizedExample1 // 修饰一个代码块 public void test1(int j) synchronized (this) for (int i = 0; i < 10; i++) log.info("test1 - ", j, i); log.info("test-----", j); // 修饰一个方法 public synchronized void test2(int j) for (int i = 0; i < 10; i++) log.info("test2 - ", j, i); public static void main(String[] args) SynchronizedExample1 example1 = new SynchronizedExample1(); SynchronizedExample1 example2 = new SynchronizedExample1(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() -> example1.test1(1); ); executorService.execute(() -> example2.test1(2); );
11:52:20.619 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 1 - 0
11:52:20.647 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 1 - 1
11:52:20.619 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 2 - 0
11:52:20.647 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 1 - 2
11:52:20.647 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 2 - 1
11:52:20.647 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 1 - 3
11:52:20.647 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 2 - 2
11:52:20.647 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 1 - 4
11:52:20.647 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 2 - 3
11:52:20.647 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 1 - 5
11:52:20.647 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 1 - 6
11:52:20.647 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 1 - 7
11:52:20.647 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 1 - 8
11:52:20.647 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 1 - 9
11:52:20.647 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 2 - 4
11:52:20.647 [pool-1-thread-1] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test-----
11:52:20.647 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 2 - 5
11:52:20.647 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 2 - 6
11:52:20.647 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 2 - 7
11:52:20.647 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 2 - 8
11:52:20.647 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test1 2 - 9
11:52:20.647 [pool-1-thread-2] INFO com.justrun.threadthink.sync.SynchronizedExample1 - test-----
以上是关于什么是线程安全性?如何线程安全的主要内容,如果未能解决你的问题,请参考以下文章