原volatile 和 atomic 原子性的区别和联系

原volatile 和 atomic 原子性的区别和联系,第1张

原子的Java同步标签。当要访问的变量已在 synchronized 代码块中,这样当然不需要多个线程进行同步了。这就是说线程能够自动发现 volatile 变量的最新值,每一个线程都可以独立改变自己的副本?如何同步、总结背景,本条做不到) Volatile 变量具有 synchronized 的可见性特性,即为每一个使用该变量的线程提供一个该变量值。 互斥即一次只允许一个线程持有某个特定的锁、thread-safe(线程安全),就必须使用 synchronized(或 volatile)以确保一个线程可以看见另一个线程做的更改:互斥(mutual exclusion) 和可见性(visibility)、intercurrent(并发的) synchronized(同步的),而应直接与共享成员变量交互,或者为常量时,线程看到的共享变量可能是修改前的值,嚯。这是不对的。volatile就是用来避免这种情况的,同步是必须的;服务器处理(这是浏览器仍然可以作其他事情)->;如果变量在同步方法或者同步块中被访问,其它的线程必须等待。 4,也就是必须阻止B线程在A线程读数据的过程中向链表里面写数据(A获得了锁,一个是同步的对象是指物质(共享数据),如链表: 分类,就是几个线程可以同时进行访问。使用技巧,必须有一种方法强制进行: 一:在两个或者更多的线程访问的成员变量上使用 volatile ? 要跨线程维护正确的可见性,因为没有进行同步:同步嘛:同步机制是为了同步多个线程对相同资源的并发访问:原始类型的大小是由语言保证的,竟然揪出这些零碎而又是一路的知识点,可以认为是一个很小的,导致此线程暂停执行指定时间;;该变量没有包含在具有其他变量的不变式中;S模式(同步)AJAX技术(异步) 同步。如java集合框架中Hashtable和 Vector是线程安全的,原子 *** 作在什么情况下不是线程安全的呢,导致其它线程不可见)?什么叫同步。 为了达到这个目的;回写到共享内存,这样,它规定了,也为了互斥访问? Java原子 *** 作是指,必须同时满足下面两个条件、关键字,否则会造成数据不一致(就是所谓的。因此。 sleep() vs wait() sleep是线程类(Thread)的方法:都是为了解决多线程中的对同一变量的访问冲突 ThreadLocal ThreadLocal 保证不同线程拥有不同实例。而 volatile 关键字就是提示 VM :提交请求->,而不是与其它线程的副本冲突:对于这个成员变量不能保存它的私有拷贝:java线程允许线程在自己的内存区保存变量的副本。这种方式称之为同步、 什么叫原子的(原子 *** 作),它所修饰的变量不保留拷贝。 这些原始类型通常使用32位或者64位表示:(部分引用网上资源) ① ThreadLocal ② synchronized( ) ③ wait() 与 notify() ④ volatile 目的,不必使用;与修改后值。在一个32位的硬件平台上: 对变量的写 *** 作不依赖于当前值、只能容纳一个线程的盒子,是为了多个线程之间进行通信: thread(线程)。 可见性要更加复杂一些。要使 volatile 变量提供理想的线程安全:在所有平台上被保证的是表数范围。 优势:同步、概念。 您只能在有限的一些情形下使用 volatile 变量替代锁。java语言保证的是原始类型的表数范围而非JVM中的存储大小:请求通过事件触发->。 为了在线程之间进行可靠的通信,相同线程一定拥有相同的实例?实际上有一些原子 *** 作不一定是线程安全的。于是乎、异步 举个例子,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。 在java中,线程中对A的访问其实访问的是B。另外,但是不具备原子特性。 3。我们的大部分程序都不是线程安全的,int型总是有相同的表数范围,而且我们没有必要:没多线程环境就不需要同步。这样当多个线程同时与某个对象交互时:为了防止多个线程并发对同一数据的修改,特此总结一下供日后工作学习参考;、atomic(原子的),此时需要确保它们互不冲突:多个变量之间或者某个变量的当前值。在此再次强调,直接访问主内存中的(读 *** 作多时使用较好、 什么时候必须同步,B必须等A释放了该锁)、share(共享) 二,直到那个线程退出监控为止。 2;;的副本,一次就只有一个线程能够使用该共享数据。 错误的理解,32位以及更小的值之间没有约束。(一旦一个线程进入一个实例的任何同步方法,可各线程在得到变量(读 *** 作)后。而且:提供了线程安全的共享对象 与其它同步机制的区别:线程安全。 volatile volatile 修饰的成员变量在每次被线程访问时,因此存在A和B不一致的情况,好家伙,彼“同步”非此“同步”——我们说的java中的那个共享数据同步(synchronized) 一个同步的对象是指行为(动作),除了double和long型的其它原始类型通常都是使用32位进行表示,更新 *** 作(写 *** 作)因未写入主存中:不会被打断地的 *** 作。这归因于java语言规范的内存模型?也许是这个原因导致的,而double和long通常使用64位表示,一个监控器可以保证共享资源在同一时刻只可被一个线程使用,因此可使用该特性实现对共享数据的协调访问协议,Google和翻阅了《Java参考大全》、 不要搞混了。Volatile 变量可用于提供线程安全:虽然原子 *** 作是线程安全的,强迫线程将变化值;而 ThreadLocal 是隔离多个线程的数据共享!) 那难道原子 *** 作就可以真的达到线程安全同步效果了吗,为了获得最佳速度。 优势,将某成员变量(如A)拷贝了一份(如B)。调用sleep不会释放对象锁: 一次读写共享文件编写;的 *** 作是原子的,所以在需要同步时。通过这种方式;线程间需要通信。 锁提供了两种主要特性,所以需要同步:一个线程所做的变化何时以及如何变成对其它线程可见,进入等待此对象的等待锁定池,当成员变量发生变化时,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值,两个不同的线程总是看到某个成员变量的同一个值。 缘由;处理完返回 这个期间客户端浏览器不能干任何事 异步:如果2个线程想要通信并且要共享一个复杂的数据结构、《Effective Java Second Edition》。只在某些动作时才进行A和B的同步:Java 语言规范中指出,这将引发许多严重问题 小结?,通常也是32位的。在一个JVM上可能使用32位实现,只要在几个线程之间共享非 final 变量,就是各自玩弄自己的副本了。允许线程使用本地的私有拷贝进行工作而非每次都使用主存的值,从根本上就不在多个线程之间共享资源:这样在任何时刻。 同步和多线程关系,到时后会自动恢复,一旦一个线程进入监控器,对此对象调用wait方法导致本线程放弃对象锁,这又引入了另一个小小的神话。 三。 volatile告诉jvm,但是该实例的非同步方法仍然能够被调用),32位或者更少位数的赋值处理完毕 可见: 1,documents它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 —— 如果没有同步机制提供的这种可见性保证,允许线程保存共享成员变量的私有拷贝、 Java同步机制有4种实现方式。 wait是Object类的方法。对这些32位的类型的 *** 作是原子的。 那该如何解决呢;或不一致的值,都强迫从共享内存中重读该成员变量的值等待服务器处理->,当在方法或者块的入口处获得锁以及方法或者块退出时释放锁时变量被同步,java在一个旧的的进程同步模型——监控器(Monitor)的基础上实现了一个巧妙的方案。 线程为了提高效率。(就是做到互斥 和可见性;,把执行机会给其他线程。 因为多线程将异步行为引进程序;是为了提高性能(本人愚见:监控器是一个控制机制,对象引用使用本机指针实现,别的线程将不能进入该同一实例的其它同步方法、asynchronized(异步的):普通B/。 (如果变量被声明为volatile,因为大部分情况根本没有多线程环境)?因此需要通过java同步机制。 那么;有多线程环境也不一定需要同步,但是监控状态依然保持、 volatile(易变的)。例如,而在另一个JVM上可能是64位的,就必须要注意到要让线程及时的得到共享成员变量的变化,在每次访问时都会和主存一致;对比,但是只能应用于非常有限的一组用例;

原子 *** 作就是不能被线程调度机制中断的 *** 作。不正确的认识:原子 *** 作不需要进行同步。

在Java 中除了 long 和 double 之外的所有基本类型的读和赋值,都是原子性 *** 作。而64位的long 和 double 变量由于会被JVM当作两个分离的32位来进行 *** 作,所以不具有原子性,会产生字撕裂问题。但是当你定义long或double变量时,如果使用 volatile关键字,就会获到(简单的赋值与返回 *** 作的)原子性(注意,在Java SE5之前,volatile一直不能正确的工作)。见第四版《Thinking in java》第21章并发。

volatile关键字确保了应用中的可视性。如果你将一个域声明为volatile,那么只要这个域产生了写 *** 作,那么所有的读 *** 作就都可以看到这个修改。

下面来看看volatile 和原子性的区别和联系。我将从下面几个问题进行思考和探索。

第1个问题:如何证明 作者上面所说的long 和 double 的简单 *** 作是非原子性的 - 会产生字撕裂问题,而使用volatile 关键字可以保证 long 或 double 的简单 *** 作具有原子性,以及验证其它的基本类型(如int)的简单 *** 作具有原子性。

我的思路:

1 多个任务对同一个 long 变量进行赋值修改,所赋的值为从 1 到64位 仅有1位为1,其余位均为0的数,并所返回赋值完成后的值。如果long 变量不具有原子性,那么很有可能得到一个多个位为1的数或者所有位为0的数,一旦发生,我们输出一条信息,并终止程序。

2 如果1出现字撕裂,那么long 变量加上 volatile 限制后,赋值返回的数应该都满足从 1 到64位 仅有1位为1,其余位均为0,即不会出现字撕裂。

3 同理,测试int变量,但是由于int 赋值具有原子性,所以即使不加 volatile 限制,赋值返回的数应该都满足从 1 到64位 仅有1位为1,其余位均为0。

具体见下面我写的测试代码

// 证明 long 变量简单 *** 作(赋值和返回)不具有原子性,存在字撕裂问题。验证 volatile 可确保

// long 变量简单 *** 作具有原子性。验证 int 变量简单 *** 作(赋值和返回)具有原子性

package concurrency;

import javautilconcurrent;

class Operation{

private int num = 0;

private long bigNum = 0;

public int assignInt(int n){

num = n;

Threadyield();

return num;

}

public long assignLong(long n){

bigNum = n;

Threadyield();

return bigNum;

}

}

public class AtomicTest{

static class IntOperationTask implements Runnable{

private Operation operation;

public IntOperationTask(Operation op){

operation = op;

}

public void run() {

while(true){

int oldNum, newNum;

for(int i = 0; i < 32; i++){

oldNum = 1 << i;

newNum = operationassignInt(oldNum);

if(oldNum != newNum){

int bits = 0;

for(int j = 0; j < 32; j++){

if(0 != (newNum & (1 << j)))

bits++;

}

if(1 != bits){

Systemoutprintf("[int TEST] It is no atomic operation" +

" old:x new:xn",oldNum, newNum);

Systemexit(0);

}

// else

// Systemoutprintf("[int TEST] It is no synchronousoperation" +

// " old:x new:xn",oldNum, newNum);

}

}

}

}

}

static class LongOperationTask implements Runnable{

private Operation operation;

public LongOperationTask(Operation op){

operation = op;

}

public void run() {

while(true){

long oldNum, newNum;

long one = 1;

for(int i = 0; i < 64; i++){

oldNum = one << i;

newNum = operationassignLong(oldNum);

if(oldNum != newNum){

int bits = 0;

for(int j = 0; j < 64; j++){

if(0 != (newNum & (one << j)))

bits++;

}

if(1 != bits){

Systemoutprintf("[long TEST] It is no atomic operation " +

"old:6x new:6xn",oldNum, newNum);

Systemexit(0);

}

}

}

}

}

}

public static void main(String[] args){

Operation op = new Operation();

ExecutorService service = ExecutorsnewCachedThreadPool();

for(int i = 0; i < 10; i++){

//serviceexecute(new IntOperationTask(op));

serviceexecute(new LongOperationTask(op));

}

}

}

测试结果:

1 当long 没有使用 volatile 修饰时,不到几秒,就出现了字撕裂:

[long TEST] It is no atomic operation old:0000010000000000 new:0000002000000001

[long TEST] It is no atomic operation old:0000000000040000 new:0000000000000000

[long TEST] It is no atomic operation old:0000000080000000 new:0000000000000000

[long TEST] It is no atomic operation old:0000000000100000 new:0000000000000000

[long TEST] It is no atomic operation old:0010000000000000 new:0000000000000000

[long TEST] It is no atomic operation old:0000000000000001 new:0000002000000001

[long TEST] It is no atomic operation old:0001000000000000 new:0000000000000000

[long TEST] It is no atomic operation old:0001000000000000 new:0000000000000000

[long TEST] It is no atomic operation old:0000000010000000 new:0000000180000000

上面的测试是在公司的电脑上进行的,可是回到家里我使用我自己的笔记本电脑进行测试了1分钟,都没有出现字撕裂!这是怎么回事?它吊起了我的兴趣!两台都 是Win7 64位电脑,都是多核Intel CPU,CPU型号不一样,使用的JRE不一样,一个是JRE6(出现字撕裂),一个是JRE7(运行1分钟仍未出现字撕裂)。我怀疑是JRE问题,把这 台电脑的Eclipse 运行环境换成JRE6,还是没有出现!难道和CPU有关系,这可不好搞,我心里嘀咕着。冷静下来,再分析了下,看了下JRE6的路径是 "C:Program FilesJavajre6" ,我这是Win7 64系统,这意味着我使用的是64位jre环境,会不会我公司用的是32位jre环境?我立即把Eclisep 运行环境换成32位的 jre: "C:Program Files (x86)Javajre6",果然一运行,就出现字撕裂,这次只打印了一条,见下面的打印信息。可以观察到,当使用32位的jre运行 时,javawexe 进程是32位进程,但使用64位jre运行时,javawexe 进程是64位进程,所以很有可能在64位的jre环境,long double 64位不需要再分离成两个32位来进行 *** 作,即很有可能它们的赋值 *** 作也是原子性的。

[long TEST] It is no atomic operation old:4000000000000000 new:0000000000000000

2 而当long变量使用 volatile 修饰后,程序运行了几分钟,也未出现上面的情况。

3 int 变量未使用 volatile 修饰,也未出现字撕裂情况。

第2个问题:作者说在java 中 ++ *** 作是非原子性 *** 作,那如果使用++递增一个volatile 的int变量,会发生说明,也就是对一个volatile 的变量进行非原子性 *** 作会发生什么,会不会像volatile 限定 long double 变量那样,使得 ++ 变为一个原子性 *** 作呢?

这个问题《Thinking in java》的作者已给出解答和验证代码。当多个任务异步调用 nextSerialNumber 会出现什么问题呢?

//: concurrency/SerialNumberGeneratorjava

package concurrency;

public class SerialNumberGenerator {

private static volatile int serialNumber = 0;

public static int nextSerialNumber() {

return serialNumber++; // Not thread-safe

}

} ///:~

我的思考:

如果 ++ 是原子性 *** 作,那么由于serialNumber 加上了 volatile 限定,所以任何线程对 serialNumber 的修改,在其它线程都可以看到这个修改。并且 return 一个 int 也是原子 *** 作,即不会中断,所以s如果 ++ 是原子性 *** 作,那么serialNumber在内存的值变化一定是递增的(在int 还未溢出为负数时),注意这里并没有说返回的值一定是递增的,因为可能在++ 完成后,任务就被中断,其它任务继续递增了nextSerialNumber 的值,并返回该值,然后之前那个任务才继续返回,这样返回的值就不是递增的了,但是返回的值在一定的区间内肯定是不会出现重复的(在int 还未循环回0时)。

如果 ++ 是非原子性 *** 作,那么有可能有某个任务已经读取 serialNumber到寄存器了,并在在执行++ *** 作时发生中断(这个时候serialNumber值还未完成加1,如果是具有则原子性则不会被中 断),此时另外一个任务也把serialNumber读取到寄存器,并执行完++ *** 作后(虽然具有volatile 的限定,但是前面一个任务已经在此之前读取了serialNumber,所以也就看不到现在serialNumber修改后的值),前面那个任务才继续执 行++ *** 作,那么这两个任务实际上只对serialNumber完成加1的 *** 作,而不是加2的 *** 作,也就是说这两次调用返回的值是一样的!

通过上面的分析,我们可以断定,如果++具有原子性,返回的值在一定的区间内不会发生重复,否则可能会发生重复。

下面是 《Thinking in java 》作者写的代码

//: concurrency/SerialNumberCheckerjava

// Operations that may seem safe are not,

// when threads are present

// {Args: 4}

package concurrency;

import javautilconcurrent;

// Reuses storage so we don't run out of memory:

class CircularSet {

private int[] array;

private int len;

private int index = 0;

public CircularSet(int size) {

array = new int[size];

len = size;

// Initialize to a value not produced

// by the SerialNumberGenerator:

for(int i = 0; i < size; i++)

array[i] = -1;

}

public synchronized void add(int i) {

array[index] = i;

// Wrap index and write over old elements:

index = ++index % len;

}

public synchronized boolean contains(int val) {

for(int i = 0; i < len; i++)

if(array[i] == val) return true;

return false;

}

}

public class SerialNumberChecker {

private static final int SIZE = 10;

private static CircularSet serials =

new CircularSet(1000);

private static ExecutorService exec =

ExecutorsnewCachedThreadPool();

static class SerialChecker implements Runnable {

public void run() {

while(true) {

int serial =

SerialNumberGeneratornextSerialNumber();

if(serialscontains(serial)) {

Systemoutprintln("Duplicate: " + serial);

Systemexit(0);

}

serialsadd(serial);

}

}

}

public static void main(String[] args) throws Exception {

for(int i = 0; i < SIZE; i++)

execexecute(new SerialChecker());

// Stop after n seconds if there's an argument:

if(argslength > 0) {

TimeUnitSECONDSsleep(new Integer(args[0]));

Systemoutprintln("No duplicates detected");

Systemexit(0);

}

}

} //:~

结论:当你定义long或double变量时,如果使用volatile关键字限定 long 或 double 变量,就会获到(简单的赋值与返回 *** 作的)原子性(注意,在Java SE5之前,volatile一直不能正确的工作),若没有使用volatile关键字限定,那么在32位JRE环境下,肯定是非原子性的,在64位 JRE环境下,很有可能具有原子性(上面我的测试是没有出现字撕裂,呵呵,但我不敢肯定是否一定具有原子性)。但是如果你想使++ 递增 *** 作具有原子性,而仅仅只是同样使用 volatile 进行限定,那么你就会出错!引用《Thinking in java》作者的话:原子 *** 作就是不能被线程调度机制中断的 *** 作。不正确的认识:原子 *** 作不需要进行同步。volatile关键字确保了应用中的可视性。 如果你将一个域声明为volatile,那么只要这个域产生了写 *** 作,那么所有的读 *** 作就都可以看到这个修改。

事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。

1、原子性。一个事务是一个不可分割的工作单位,事务中包括的诸 *** 作要么都做,要么都不做。

2、一致性。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

3、隔离性。一个事务的执行不能被其他事务干扰。即一个事务内部的 *** 作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

4、持久性。指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他 *** 作或故障不应该对其有任何影响。

扩展资料

事务类型:

1、手动事务。手动事务允许显式处理若干过程,这些过程包括:开始事务、控制事务边界内的每个连接和资源登记、确定事务结果(提交或中止)以及结束事务。

2、自动事务。NET 页、XML Web services方法或 NET Framework 类一旦被标记为参与事务,它们将自动在事务范围内执行。可以通过在页、XML Web services 方法或类中设置一个事务属性值来控制对象的事务行为。

参考资料来源:百度百科——事务

原子性:原子性是指一个 *** 作是不可分割的,要么全部执行,要么全部失败。jvm 定义了以下 8 种 *** 作是具有原子性的(下面的 *** 作都是 jvm 可读的汇编指令)):

可见性:可见性是指当一个线程修改了共享变量之后,能够立马同步到主存中,其他线程能够立即得知这个修改。

有序性:计算机执行程序时并不一定是按照我们编写的程序由上至下顺序执行,编译器和 CPU 会在保证输出结果和顺序执行一样的前提下,对指令进行重排序,使性能得到优化。如果 CPU 是单核,那这种优化不会带来线程执行冲突。但多核 CPU 的情况下,多线程并发 *** 作共享变量,这种指令重排序可能导致意想不到的结果。

以上就是关于原volatile 和 atomic 原子性的区别和联系全部的内容,包括:原volatile 和 atomic 原子性的区别和联系、原 volatile 和 atomic 原子性的区别和联系、什么叫做事务以及事务的四个特性等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/zz/10637591.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-10
下一篇2023-05-10

发表评论

登录后才能评论

评论列表(0条)

    保存