简体   繁体   English

原子操作和多线程

[英]Atomic Operations and multithreading

Recently I was reading a tutorial, in that I came across a statement that says.. 最近我正在阅读一个教程,因为我发现了一个声明说...

"The Java language specification guarantees that reading or writing a variable is an atomic operation(unless the variable is of type long or double ). Operations variables of type long or double are only atomic if they declared with the volatile keyword." “Java语言规范保证了读取或写入的变量是一个原子操作(除非该变量的类型的longdouble )类型的操作变量longdouble只有原子的,如果他们与申报volatile关键字。”

AtomicInteger or AtomicLong that provides methods like getAndDecrement() , getAndIncrement() and getAndSet() which are atomic. AtomicIntegerAtomicLong提供getAndDecrement()getAndIncrement()getAndSet()等原子方法。

I got confused a bit with the above statement.. could you please clarify when to use AtomicInteger or AtomicLong classes. 我对上述陈述感到困惑。你能否澄清何时使用 AtomicIntegerAtomicLong类。

Doing a = 28 (with a being an int ) is an atomic operation. a = 28 (带有a int )是一个原子操作。 But doing a++ is not an atomic operation because it requires a read of the value of a, an incrementation, and a write to a of the result. 但是,执行a++不是原子操作,因为它需要读取a的值,增量和写入结果。 As a result, if you used a++ to implement a thread-safe counter, you could have two threads reading the value concurrently (26 for example), then have both increment it and writing it concurrently, resulting in 27 as a result, instead of 28. 因此,如果您使用a++来实现线程安全计数器,您可以让两个线程同时读取该值(例如26),然后同时增加它并同时写入它,结果导致27,而不是28。

AtomicInteger solves this issue by providing atomic operations like the ones you listed. AtomicInteger通过提供与您列出的原子操作类似的原子操作来解决此问题。 In my example, you would use incrementAndGet() for example, which would guarantee the end value is 28 and not 27. 在我的示例中,您将使用incrementAndGet() ,这将保证结束值为28而不是27。

Atomic means the operation completes without any possibility for something to happen between. 原子意味着操作完成,没有任何可能发生的事情。 eg. 例如。 getAndDecrement(), on AtomicInteger, guarantees that the variable is returned AND decremented at the same time. AtomicInteger上的getAndDecrement()保证变量同时返回和递减。

If it was not an atomic operation, the possibility would exist for the value to get decremented (eg. from 3 to 2), then modified by another thread (eg. changing it from 2 to 5), then returned as 5. 如果它不是原子操作,则可能存在值递减(例如从3到2),然后由另一个线程修改(例如,将其从2更改为5),然后返回为5。

You need an AtomicInteger if you need to read a variable and write a result depending on the read value . 如果需要读取变量并根据读取值写入结果,则需要AtomicInteger For instance, i++ reads i (eg 3 ) and writes i+1 (eg 4 ). 例如, i++读取i (例如3 )并写入i+1 (例如4 )。 A thread may be interrupted meanwhile, and three other threads increment i too. 一个线程可以同时中断,和其他三个线程递增i了。 Now that we get back, i actually has the value 6 but our thread still writes 4 , based on what it read beforehand. 现在我们回来了, i实际上有值6但我们的线程仍然根据它事先读取的内容写入4

AtomicInteger.getAndIncrement ensures you're not interrupted and therefore always incrementing properly. AtomicInteger.getAndIncrement确保您不会被中断 ,因此总是正确递增。 Moreover, the result is always flushed into memory , whereas a non-volatile i might not be flushed to memory. 此外,结果总是刷新到内存中 ,而非易失性i可能不会刷新到内存中。 In this case other threads might not even see the changes. 在这种情况下,其他线程甚至可能看不到更改。

I think what it means is that long and double - read operation is atomic and write operation is atomic. 我认为这意味着长读和双读操作是原子的,写操作是原子的。 But a read + write is not atomic. 但读取+写入不是原子的。

volatile long num;
num = num+1

The above is not thread safe. 以上不是线程安全的。 There read and write are two separate operations. 读写是两个独立的操作。 Each of those are guaranteed to be atomic, but the whole expression is not. 每个都保证是原子的,但整个表达不是。

To make it thread safe you would need to use an AtomicLong and use the getAndIncrement function. 要使其线程安全,您需要使用AtomicLong并使用getAndIncrement函数。

You use int or long based on the upper/lower limit on the range of numbers you are dealing with. 您可以根据要处理的数字范围的上限/下限使用int或long。 Please do not mix non-atomic behavior of long with AtomicLong. 请不要将长原子的非原子行为与AtomicLong混合。 Whatever you have written above is correct but you are probably mixing both concepts. 无论你上面写的是什么都是正确的,但你可能会混合这两个概念。 AtomicXXX are more useful in cases where you are doing "compare & set" kind of operations. 在您进行“比较和设置”操作的情况下,AtomicXXX更有用。 For example even when int can be modified/read atomically following code will be incorrect in multithreaded environment : 例如,即使在多线程环境中代码在原子上被修改/读取也是不正确的:

int i =10
..
..
..
if(i == 10) i++;

in multithread environment two threads can access this code atomically and updated value of i and making it come in consistent state. 在多线程环境中,两个线程可以原子方式访问此代码并更新i的值并使其处于一致状态。 SO deal with such situations normally you guard the code "if(i == 10) i++;" 因此,处理这种情况通常会保护代码“if(i == 10)i ++;” with synchronized block. 与同步块。 However AtomicInteger class provides the API to achieve such things without using synchronized blocks which are slower. 但是,AtomicInteger类提供了实现此类功能的API,而不使用速度较慢的同步块。 Same is the case of AtmoicLong APIs AtmoicLong API的情况也是如此

atomicity of an operation is required when you mutate a variable. 变异变量时需要操作的原子性。 doing int a = 10; int a = 10; is an atomic operation but its not the one which will give you the problem. 是一个原子操作,但它不会给你提供问题。 the problem giving operations usually are mutating ones like a++ or a = a + 2; 提供操作的问题通常是变异的,如a++a = a + 2; and so on. 等等。

Java Specification guarantees that 'reading' and 'writing' are atomic operations not their combinations. Java规范保证“读取”和“写入”是原子操作而不是它们的组合。 so an operation which 'reads, adds 1 and then writes the result back' is not atomic as per specification. 因此,根据规范,“读取,添加1然后将结果写回”的操作不是原子操作。 such operations are called compound operations and they usually need to be atomic in context of their usage in our code. 这些操作称为复合操作,它们通常需要在我们的代码中使用它们的上下文。

Atomic types help solve this problem. 原子类型有助于解决此问题。 using incrementAndget() on an atomic type makes 'reads, adds 1 and then writes the result back and reads the new result' a single atomic operation in context to thread safety. 在原子类型上使用incrementAndget()使得'读取,添加1然后将结果写回并读取新结果'在上下文中的单个原子操作到线程安全性。

Hope this helps. 希望这可以帮助。 By the way you should read this ( http://walivi.wordpress.com/2013/08/24/concurrency-in-java-a-beginners-introduction/ ) article about basics of concurrency and threads. 顺便说一句,你应该阅读这篇关于并发和线程基础知识的文章( http://walivi.wordpress.com/2013/08/24/concurrency-in-java-a-beginners-introduction/ )。 it explains such stuff beautifully. 它很好地解释了这些东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM