-
Java中线程安全的体现(原子性、可见性、有序性)
2019-10-11 17:51:16Java中如何保证线程安全性(1.8w阅读量,12赞) 5、并发编程的3个概念:原子性、可见性、有序性(5k阅读量,4赞) Java并发编程:volatile关键字解析 1、线程安全在三个方面体现 1.1、原子性: 提供互斥访问,...0、相关文章:
Java中如何保证线程安全性(1.8w阅读量,12赞)
5、并发编程的3个概念:原子性、可见性、有序性(5k阅读量,4赞)
1、线程安全在三个方面体现
1.1、原子性:
提供互斥访问,同一时刻只能有一个线程对数据进行操作(atomic [əˈtɑːmɪk] 、synchronized);
1.2、可见性:
一个线程对主内存的修改可以及时地被其他线程看到(synchronized、volatile);
1.3、.有序性:
一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)。
2、原子性
原子性的实现有两种方式:atomic类和synchronized。
2.1、JDK里面提供了很多atomic类,AtomicInteger,AtomicLong,AtomicBoolean等等,它们是通过CAS完成原子性。
2.2、synchronized是一种同步锁,通过锁实现原子操作。
JDK提供锁分两种:一种是synchronized,依赖JVM实现锁,因此在这个关键字作用对象的作用范围内是同一时刻只能有一个线程进行操作;另一种是LOCK,是JDK提供的代码层面的锁,依赖CPU指令,代表性的是ReentrantLock。
synchronized修饰的对象有四种:
- (1)修饰代码块,作用于调用的对象;
- (2)修饰方法,作用于调用的对象;
- (3)修饰静态方法,作用于所有对象;
- (4)修饰类,作用于所有对象。
3、可见性
对于可见性,JVM提供了synchronized和volatile。
4、有序性
有序性是指,在JVM中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。
可以通过volatile、synchronized、lock保证有序性。
-
Java线程安全性
2019-05-23 17:17:45在Java中,线程安全性是指:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替进行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程...在Java中,线程安全性是指:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替进行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。
线程安全性体现在三个方面:原子性、可见性、有序性。
一. 原子性
原子性提供了互斥访问,同一时刻只能有一个线程来对它进行操作。
保证原子性有两种方式:
(1)Atomic包
- AtomicXXX:CAS、Unsafe.compareAndSwapInt
- AtomicLong、LongAdder(两者区别:https://blog.csdn.net/yao123long/article/details/63683991)
- AtomicReference、AtomicReferenceFieldUpdater(添加的类属性需要使用volatile修饰)
- AtomicStampReference:解决CAS的ABA问题
(2)锁
- synchronized:依赖JVM,修饰代码块、方法、静态方法、类(子类继承父类后,父类的synchronized修饰的方法不起作用(synchronized不属于方法声明的一部分),子类需要自己显式声明synchronized关键字。)
- Lock:依赖特殊的CPU指令,代码实现,ReentrantLock
二. 可见性
可见性指一个线程对主内存的修改可以及时的被其他线程观察到。
volatile:通过加入内存屏障和禁止重排序优化来实现。(不保证原子性)
- 对volatile变量写操作时,会在写操作后加入一条store屏障指令,将本地内存中的共享变量值刷新到主内存;
- 对volatile变量读操作时,会在读操作前加入一条load屏障指令,从主内存中读取共享变量。
使用volatile必须具备2个条件:①对变量的写操作不依赖当前值;②该变量没有包含在具有其他变量的不变式中。
三. 有序性
有序性指一个线程观察其他线程中的指令执行顺序,由于指令重排序的存在,该观察结果一般杂乱无序。
happens-before原则保证指令不能重排,共有8条原则:
- 程序顺序原则:一个线程内保证语义的串行性。
- volatile规则:volatile变量的写,先发生于读,这保证了volatile变量的可见性。
- 锁规则:解锁(unlock)必然发生在随后的加锁(lock)前。
- 传递性:A先于B,B先于C,那么A必然先于C。
- 线程的start()方法先于它的每一个动作。
- 线程的所有操作先于线程的终结(Thread.join())。
- 线程的中断(interrupt())先于被中断线程的代码。
- 对象的构造函数执行、结束先于finalize()方法。
-
Java中如何保证线程安全性
2018-05-12 16:58:10一、线程安全在三个方面体现1.原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);2.可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);3....一、线程安全在三个方面体现
1.原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);
2.可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);
3.有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)。
接下来,依次分析。
二、原子性---atomic
JDK里面提供了很多atomic类,AtomicInteger,AtomicLong,AtomicBoolean等等。
它们是通过CAS完成原子性。
我们一次来看AtomicInteger,AtomicStampedReference,AtomicLongArray,AtomicBoolean。
(1)AtomicInteger
先来看一个AtomicInteger例子:
public class AtomicIntegerExample1 { // 请求总数 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.get()); } private static void add() { count.incrementAndGet(); } }
我们可以执行看到最后结果是5000是线程安全的。
那么看AtomicInteger的incrementAndGet()方法:
再看getAndAddInt()方法:
这里面调用了compareAndSwapInt()方法:
它是native修饰的,代表是java底层的方法,不是通过java实现的 。
再重新看getAndAddInt(),传来第一个值是当前的一个对象 ,比如是count.incrementAndGet(),那么在getAndAddInt()中,var1就是count,而var2第二个值是当前的值,比如想执行的是2+1=3操作,那么第二个参数是2,第三个参数是1 。
变量5(var5)是我们调用底层的方法而得到的底层当前的值,如果没有别的线程过来处理我们count变量的时候,那么它正常返回值是2。
因此传到compareAndSwapInt方法里的参数是(count对象,当前值2,当前从底层传过来的2,从底层取出来的值加上改变量var4)。
compareAndSwapInt()希望达到的目标是对于var1对象,如果当前的值var2和底层的值var5相等,那么把它更新成后面的值(var5+var4).
compareAndSwapInt核心就是CAS核心。
关于count值为什么和底层值不一样:count里面的值相当于存在于工作内存的值,底层就是主内存。
(2)AtomicStampedReference
接下来我们看一下AtomicStampedReference。
关于CAS有一个ABA问题:开始是A,后来改为B,现在又改为A。解决办法就是:每次变量改变的时候,把变量的版本号加1。
这就用到了AtomicStampedReference。
我们来看AtomicStampedReference里的compareAndSet()实现:
而在AtomicInteger里compareAndSet()实现:
可以看到AtomicStampedReference里的compareAndSet()中多了 一个stamp比较(也就是版本),这个值是由每次更新时来维护的。
(3)AtomicLongArray
这种维护数组的atomic类,我们可以选择性地更新其中某一个索引对应的值,也是进行原子性操作。这种对数组的操作的各种方法,会多处一个索引。
比如,我们看一下compareAndSet():
(4)AtomicBoolean
看一段代码:
public class AtomicBooleanExample { private static AtomicBoolean isHappened = new AtomicBoolean(false); // 请求总数 public static int clientTotal = 5000; // 同时并发执行的线程数 public static int threadTotal = 200; 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(); test(); semaphore.release(); } catch (Exception e) { log.error("exception", e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("isHappened:{}", isHappened.get()); } private static void test() { if (isHappened.compareAndSet(false, true)) { log.info("execute"); } } }
执行之后发现,log.info("execute");只执行了一次,且isHappend值为true。
原因就是当它第一次compareAndSet()之后,isHappend变为true,没有别的线程干扰。
通过使用AtomicBoolean,我们可以使某段代码只执行一次。
三、原子性---synchronized
synchronized是一种同步锁,通过锁实现原子操作。
JDK提供锁分两种:一种是synchronized,依赖JVM实现锁,因此在这个关键字作用对象的作用范围内是同一时刻只能有一个线程进行操作;另一种是LOCK,是JDK提供的代码层面的锁,依赖CPU指令,代表性的是ReentrantLock。
synchronized修饰的对象有四种:
(1)修饰代码块,作用于调用的对象;
(2)修饰方法,作用于调用的对象;
(3)修饰静态方法,作用于所有对象;
(4)修饰类,作用于所有对象。
修饰代码块和方法:
@Slf4j public class SynchronizedExample1 { // 修饰一个代码块 public void test1(int j) { synchronized (this) { for (int i = 0; i < 10; i++) { log.info("test1 {} - {}", j, i); } } } // 修饰一个方法 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(() -> { example1.test1(2); }); //二 executorService.execute(() -> { example2.test2(1); }); executorService.execute(() -> { example2.test2(2); }); //三 executorService.execute(() -> { example1.test1(1); }); executorService.execute(() -> { example2.test1(2); }); } }
执行后可以看到对于情况一,test1内部方法块作用于example1,先执行完一次0-9输出,再执行下一次0-9输出;情况二,同情况一类似,作用于example2;情况三,可以看到交叉执行,test1分别独立作用于example1和example2,互不影响。
修饰静态方法和类:
@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.test1(1); }); executorService.execute(() -> { example2.test1(2); }); } }
test1和test2会锁定调用它们的对象所属的类,同一个时间只有一个对象在执行。
四、可见性---volatile
对于可见性,JVM提供了synchronized和volatile。这里我们看volatile。
(1)volatile的可见性是通过内存屏障和禁止重排序实现的
volatile会在写操作时,会在写操作后加一条store屏障指令,将本地内存中的共享变量值刷新到主内存:
volatile在进行读操作时,会在读操作前加一条load指令,从内存中读取共享变量:
(2)但是volatile不是原子性的,进行++操作不是安全的
执行后发现线程不安全,原因是执行conut++时分成了三步,第一步是取出当前内存count值,这时count值时最新的,接下来执行了两步操作,分别是+1和重新写回主存。假设有两个线程同时在执行count++,两个内存都执行了第一步,比如当前count值为5,它们都读到了,然后两个线程分别执行了+1,并写回主存,这样就丢掉了一次加一的操作。@Slf4j public class VolatileExample { // 请求总数 public static int clientTotal = 5000; // 同时并发执行的线程数 public static int threadTotal = 200; public static volatile int count = 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++; } }
(3)volatile适用的场景
既然volatile不适用于计数,那么volatile适用于哪些场景呢:
1. 对变量的写操作不依赖于当前值
2. 该变量没有包含在具有其他变量不变的式子中
因此,volatile适用于状态标记量:
线程1负责初始化,线程2不断查询inited值,当线程1初始化完成后,线程2就可以检测到inited为true了。
五、有序性
有序性是指,在JMM中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。
可以通过volatile、synchronized、lock保证有序性。
另外,JMM具有先天的有序性,即不需要通过任何手段就可以得到保证的有序性。这称为happens-before原则。
如果两个操作的执行次序无法从happens-before原则推导出来,那么它们就不能保证它们的有序性。虚拟机可以随意地对它们进行重排序。
happens-before原则:
1.程序次序规则:在一个单独的线程中,按照程序代码书写的顺序执行。
2.锁定规则:一个unlock操作happen—before后面对同一个锁的lock操作。
3.volatile变量规则:对一个volatile变量的写操作happen—before后面对该变量的读操作。
4.线程启动规则:Thread对象的start()方法happen—before此线程的每一个动作。
5.线程终止规则:线程的所有操作都happen—before对此线程的终止检测,可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。
6.线程中断规则:对线程interrupt()方法的调用happen—before发生于被中断线程的代码检测到中断时事件的发生。
7.对象终结规则:一个对象的初始化完成(构造函数执行结束)happen—before它的finalize()方法的开始。
8.传递性:如果操作A happen—before操作B,操作B happen—before操作C,那么可以得出A happen—before操作C。
-
java 线程安全性_【Java并发】线程安全性
2021-02-26 10:12:43线程安全性定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。...线程安全性
定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。
线程安全性主要体现在三个方面:原子性、可见性、有序性:
原子性:提供了互斥访问,同一时刻只能有一个线程来对它进行操作
可见性:一个线程对主内存的修改可以及时地被其他线程观察到
有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序的存在,该观察结果一般杂乱无序
原子性
原子性在 JDK 中主要由两个方面体现出来:
Atomic
一个是 JDK 中已经提供好的 Atomic 包,它们均使用了 CAS 完成线程的原子性操作(详见【Java并发】浅析 AtomicLong & LongAdder)。
另一个是使用锁的机制来处理线程之间的原子性。锁主要包括:synchronized、lock。
synchronized
依赖于 JVM 去实现锁,因此在这个关键字作用对象的作用范围内,都是同一时刻只能有一个线程对其进行操作的。synchronized 是 Java 中的一个关键字,是一种同步锁。它可以修饰的对象主要有四种:
修饰代码块:大括号括起来的代码,作用于调用的对象
修饰方法:整个方法,作用于调用的对象
修饰静态方法:整个静态方法,作用于所有对象
修饰类:括号括起来的部分,作用于所有对象
注意:如果当前类是一个父类,子类调用父类的被 synchronized 修饰的方法,不会携带 synchronized 属性,因为 synchronized 不属于方法声明的一部分。
Lock
首先要说明的就是 Lock,通过查看 Lock 的源码可知,Lock 是一个接口。ReentrantLock 是唯一实现了 Lock 接口的类,意思是“可重入锁”,并且 ReentrantLock 提供了更多的方法。
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
锁的分类
可重入锁
synchronized / ReentrantLock
可中断锁
synchronized 不可中断,Lock 可中断
公平锁
synchronized 非公平锁
ReentrantLock 和 ReentrantReadWriteLock 默认情况下非公平锁,可设置为公平锁
读写锁
ReadWriteLock / ReentrantReadWriteLock
可见性
导致共享变量在线程间不可见的原因:
线程交叉执行
重排序结合线程交叉执行
共享变量更新后的值没有在工作内存与主存间及时更新
JVM 对于可见性,提供了 synchronized 和 volatile:
synchronized
JMM 关于 synchronized 的两条规定:
线程解锁前,必须把共享变量的最新值刷新到主内存
线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值(注意:加锁与解锁是同一把锁)
volatile
volatile 的方式是:通过加入内存屏障和禁止重排序优化来实现。
对 volatile 变量写操作时,会在写操作后加入一条 store 屏障指令,将本地内存中的共享变量值刷新到主内存。
对 volatile 变量读操作时,会在读操作前加入一条 load 屏障指令,从主内存中读取共享变量。
volatile的屏障操作都是 cpu 级别的;适合状态验证,不适合累加值,volatile关键字不具有原子性。
适合状态验证,不适合累加值,volatile关键字不具有原子性
有序性
Java 内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。而 Java 提供了 volatile、synchronized、Lock,它们可以用来保证有序性。
另外,Java 内存模型具备一些先天的有序性,即不需要任何手段就能得到保证的有序性。通常被我们称为happens-before 原则(先行发生原则)。如果两个线程的执行顺序无法从 happens-before 原则推导出来,那么就不能保证它们的有序性,虚拟机就可以对它们进行重排序。
程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作
锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作
volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作(重要)
传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C
线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作
线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行
思维导图
-
java voliate 线程安全_Java中的并发——线程安全性
2021-02-26 19:16:07一.什么是线程安全性?当多个线程访问某个类时,不管运行时环境采用何种调度方式,或者这些线程将如何交替执行,并且在主调...java中如何体现原子性的:Atomic包中的类主要通过CAS实现原子性CAS的含义是:CompareAnd... -
如何保证线程安全有序性_Java并发编程(2)- 线程安全性详解
2020-12-24 02:45:29当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的线程安全性主要体现在... -
Java中的并发:线程安全性
2020-10-11 10:45:47一.什么是线程安全性? 当多个线程访问某个类时,不管运行时环境...java中如何体现原子性的: Atomic包中的类主要通过CAS实现原子性 CAS的含义是:CompareAndSwap 原理是: public final int getAndAddInt(Object va -
java实现线程安全的hashmap_浅析JDK1.8 下HashMap线程安全性
2021-03-17 15:36:24下文主要从原子性和可见性分析JDK 1.8 中HashMap的线程安全性及ConcurrentHashMap如何实现线程安全。HashMap中存在的线程安全问题:1.HashMap在读取Hash槽首元素的时候读取的是工作内存中引用所指向的对象,并发情况... -
java高并发安全性_java高并发(五)线程安全性
2021-03-05 11:28:23线程安全性体现在以下三个方面:原子性:提供了互斥访问,同一时刻只能有一个线程来对它进行操作。可见性:一个线程对主内存的修改可以及时的被其他线程观察到。有序性:一个线程观察其他线程中的指令执行顺序,由于... -
多线程中的互斥控制程序代码_Java中的并发——线程安全性
2020-11-22 15:44:18一.什么是线程安全性?当多个线程访问某个类时,不管运行时环境采用何种调度方式,或者这些线程将如何交替执行,并且在主调...java中如何体现原子性的:Atomic包中的类主要通过CAS实现原子性CAS的含义是:CompareAnd... -
如何保证线程安全有序性_java如何保证线程安全(转自网络,仅用于个人学习)...
2020-12-24 02:46:50一、线程安全在三个方面体现1.原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);2.可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);3.有序... -
【Java并发】线程安全性
2019-02-16 02:28:05线程安全性 定义:当多个线程访问某个类时,不管运行时环境采用何种...线程安全性主要体现在三个方面:原子性、可见性、有序性: 原子性:提供了互斥访问,同一时刻只能有一个线程来对它进行操作 可见性:一个线... -
Java并发编程之线程安全性
2019-03-01 20:06:12线程安全性: 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要额外的同步或协同,这个类都能表现出正确的行为,那么就称为这个类是线程安全的。 ... -
Java并发学习之线程安全性
2018-05-05 20:19:53线程安全性定义:当多个线程访问某个类或方法时,不管运行时环境采用何种调度方式或者这些进行如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类或方法是线程... -
影响java线程安全的三个因素
2018-11-09 14:09:02java的线程安全性 线程安全性:当多个线程访问某个类时,不管运行时环境采用任何调度方式或者这些进程将如何交替执行,而且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是... -
java多线程风险-线程安全性
2018-11-01 15:25:04当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么这个类就是线程安全的。 2. 线程安全方面的... -
java高并发(六)线程安全性
2019-09-16 10:49:30线程安全性体现在以下三个方面: 原子性:提供了互斥访问,同一时刻只能有一个线程来对它进行操作。 可见性:一个线程对主内存的修改可以及时的被其他线程观察到。 有序性:一个线程观察其他线程中的指令执行... -
Java并发编程(2)- 线程安全性详解
2018-10-16 15:50:12线程安全性主要体现在三个方面: 原子性:提供了互斥访问,同一时刻只能有一个线程来对它进行操作 可见性:一个线程对主内存的修改可以及时的被其他线程观察到 有序性:一个线程观察其他线程中的指令执行顺... -
二、Java多线程安全原子性之Atomic、CAS、Synchronized和Lock
2019-03-21 11:51:01线程安全性主要体现在三个方面:原子性、可见性、有序性 原子性:提供了互斥访问,同一时刻只能有一个线程来对它进行操作 可见性:一个线程对主内存的修改可以及时的被其他线程观察到 有序性:一个线程... -
Java~如何理解 Java是强类型语言 JavaScript是弱类型语言
2020-06-03 11:08:53Java 的安全性、健壮性和严谨性是强类型语言的一重要体现。 Java强类型语言所以对数据类型兼容性的要求比任何语言都要严格. 每个变量有类型,每个表达式有类型,而且每种类型是严格定义的。其次,所有的数值传递,... -
在 Java 的多线程中,如何去判断给定的一个类是否是线程安全的(另外:synchronized 同步是否就一定能保证...
2015-03-28 10:19:00同步代码块和同步方法的区别:同步代码块可以传入任意对象,同步方法中 如果多个线程检查的都是一个新的对象,不同的同步锁对不同的线程不具有排他性,不能实现线程同步的效果,这时候线程同步就失效了。 两者的... -
如何实现线程间的数据安全?
2019-03-11 12:03:15如何实现线程间的数据安全? 线程安全在三个方面体现1.原子性 2.可见性 3.有序性 1.原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作 Java中提供了很多atomic类,AtomicInteger,AtomicLong,... -
线程安全性以及Spring中@Controller、@Service的使用
2018-07-26 19:51:40线程安全性定义 多个线程同时访问一个类,不论运行时...线程安全性体现的三个方面 原子性提供互斥访问,即同一时刻只能由一个线程访问。 原子性的保障在java中的实现有两种方式: atomic包 优势:竞争激烈时...