Concurrent Random Numbers
In JDK 7, java.util.concurrent
includes a convenience class, ThreadLocalRandom
, for applications that expect to use random numbers from multiple threads or ForkJoinTask
s.
For concurrent access, using ThreadLocalRandom
instead of Math.random()
results in less contention and, ultimately, better performance.
All you need to do is call ThreadLocalRandom.current()
, then call one of its methods to retrieve a random number. Here is one example:
int r = ThreadLocalRandom.current() .nextInt(4, 77);
译文:
在JDK 7中,java.util.concurrent包括了一个便利的类,ThreadLocalRandom,对于应用程序希望用随机数在多线程中或者ForkJoinTasks.
对于并发使用,利用ThreadLocalRandom代替Math.Random()导致一些争议,基本上,性能上更好。
所有你要做的是调用ThreadLocalRandom.current(),然后调用它的方法重新获得一个随机数。这是一个实例:
int r = ThreadLocalRandom.current() .nextInt(4, 77);
For Further Reading
- Concurrent Programming in Java: Design Principles and Pattern (2nd Edition) by Doug Lea. A comprehensive work by a leading expert, who's also the architect of the Java platform's concurrency framework.
- Java Concurrency in Practice by Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, and Doug Lea. A practical guide designed to be accessible to the novice.
- Effective Java Programming Language Guide (2nd Edition) by Joshua Bloch. Though this is a general programming guide, its chapter on threads contains essential "best practices" for concurrent programming.
- Concurrency: State Models & Java Programs (2nd Edition), by Jeff Magee and Jeff Kramer. An introduction to concurrent programming through a combination of modeling and practical examples.
- Java Concurrent Animated: Animations that show usage of concurrency features.
译文:
进一步阅读
- Doug Lea的《Java的并发编程:设计原则和模式》(第二版)。一个领先的专家做了一些全面的工作。也是Java并发平台的架构师。
- Brian Goetz,Tim Peierls,Joshua Bloch,Joseph Bowbeer,David Holmes,和Doug Lea的《Java 并发实例》。
- Joshua Bloch的《高效的Java语言编程指南》(第二版),它关于线程的章节包含基本的并发编程的“最好实例”
- Jeff Magee和Jeff Kramer的《并发:状态模型与Java程序》(第二版),一个通过实例和模型来介绍并发程序的书。
- 《Java 并发动画》:展示并发特性的动画。
Questions and Exercises: Concurrency
Questions
- Can you pass a
Thread
object toExecutor.execute
? Would such an invocation make sense?
Exercises
- Compile and run
BadThreads.java
:public class BadThreads { static String message; private static class CorrectorThread
extends Thread { public void run() {
try {
sleep(1000);
} catch (InterruptedException e) {}
// Key statement 1:
message = "Mares do eat oats.";
}
} public static void main(String args[])
throws InterruptedException { (new CorrectorThread()).start();
message = "Mares do not eat oats.";
Thread.sleep(2000);
// Key statement 2:
System.out.println(message);
}
}The application should print out "Mares do eat oats." Is it guaranteed to always do this? If not, why not? Would it help to change the parameters of the two invocations of
Sleep
? How would you guarantee that all changes tomessage
will be visible in the main thread? - Modify the producer-consumer example in Guarded Blocks to use a standard library class instead of the
Drop
class.
译文:
问题和练习:并发
问题:
1.你能用一个线程对象来执行Executor.execute吗?这样调用有意义吗?
练习:
1.编译和运行BadThreads.java:
public class BadThreads { static String message; private static class CorrectorThread
extends Thread { public void run() {
try {
sleep(1000);
} catch (InterruptedException e) {}
// Key statement 1:
message = "Mares do eat oats.";
}
} public static void main(String args[])
throws InterruptedException { (new CorrectorThread()).start();
message = "Mares do not eat oats.";
Thread.sleep(2000);
// Key statement 2:
System.out.println(message);
}
}
这个程序应该打印出"Mares do eat oats."它是否保证一直这样做?如果不,为什么?它是否会改变这个睡眠参数?你会如何保证在主程序中所有的message都是可见的?
2.修改 Guarded Blocks节中生产者-消费者程序利用标准的类库程序代替Drop类。
Answers to Questions and Exercises: Concurrency
Questions
-
Question: Can you pass a
Thread
object toExecutor.execute
? Would such an invocation make sense? Why or why not?Answer:
Thread
implements theRunnable
interface, so you can pass an instance ofThread
toExecutor.execute
. However it doesn't make sense to useThread
objects this way. If the object is directly instantiated fromThread
, itsrun
method doesn't do anything. You can define a subclass ofThread
with a usefulrun
method — but such a class would implement features that the executor would not use.
Exercises
-
Exercise: Compile and run
BadThreads.java
:public class BadThreads { static String message; private static class CorrectorThread
extends Thread { public void run() {
try {
sleep(1000);
} catch (InterruptedException e) {}
// Key statement 1:
message = "Mares do eat oats.";
}
} public static void main(String args[])
throws InterruptedException { (new CorrectorThread()).start();
message = "Mares do not eat oats.";
Thread.sleep(2000);
// Key statement 2:
System.out.println(message);
}
}The application should print out "Mares do eat oats." Is it guaranteed to always do this? If not, why not? Would it help to change the parameters of the two invocations of
Sleep
? How would you guarantee that all changes tomessage
will be visible to the main thread?Solution: The program will almost always print out "Mares do eat oats." However, this result is not guaranteed, because there is no happens-before relationship between "Key statement 1" and "Key statment 2". This is true even if "Key statement 1" actually executes before "Key statement 2" — remember, a happens-before relationship is about visibility, not sequence.
There are two ways you can guarantee that all changes to
message
will be visible to the main thread:- In the main thread, retain a reference to the
CorrectorThread
instance. Then invokejoin
on that instance before referring tomessage
- Encapsulate
message
in an object with synchronized methods. Never referencemessage
except through those methods.
Both of these techniques establish the necessary happens-before relationship, making changes to
message
visible.A third technique is to simply declare
message
asvolatile
. This guarantees that any write tomessage
(as in "Key statement 1") will have a happens-before relationship with any subsequent reads ofmessage
(as in "Key statement 2"). But it does not guarantee that "Key statement 1" willliterally happen before "Key statement 2". They will probably happen in sequence, but because of scheduling uncertainities and the unknown granularity ofsleep
, this is not guaranteed.Changing the arguments of the two
sleep
invocations does not help either, since this does nothing to guarantee a happens-before relationship. - In the main thread, retain a reference to the
-
Exercise: Modify the producer-consumer example in Guarded Blocks to use a standard library class instead of the
Drop
class.Solution: The
java.util.concurrent.BlockingQueue
interface defines aget
method that blocks if the queue is empty, and aput
methods that blocks if the queue is full. These are effectively the same operations defined byDrop
— except thatDrop
is not a queue! However, there's another way of looking at Drop: it's a queue with a capacity of zero. Since there's no room in the queue for any elements, everyget
blocks until the correspondingtake
and everytake
blocks until the correspondingget
. There is an implementation ofBlockingQueue
with precisely this behavior:java.util.concurrent.SynchronousQueue
.BlockingQueue
is almost a drop-in replacement forDrop
. The main problem inProducer
is that withBlockingQueue
, theput
andget
methods throwInterruptedException
. This means that the existingtry
must be moved up a level:import java.util.Random;
import java.util.concurrent.BlockingQueue; public class Producer implements Runnable {
private BlockingQueue<String> drop; public Producer(BlockingQueue<String> drop) {
this.drop = drop;
} public void run() {
String importantInfo[] = {
"Mares eat oats",
"Does eat oats",
"Little lambs eat ivy",
"A kid will eat ivy too"
};
Random random = new Random(); try {
for (int i = 0;
i < importantInfo.length;
i++) {
drop.put(importantInfo[i]);
Thread.sleep(random.nextInt(5000));
}
drop.put("DONE");
} catch (InterruptedException e) {}
}
}Similar changes are required for
Consumer
:import java.util.Random;
import java.util.concurrent.BlockingQueue; public class Consumer implements Runnable {
private BlockingQueue<String> drop; public Consumer(BlockingQueue<String> drop) {
this.drop = drop;
} public void run() {
Random random = new Random();
try {
for (String message = drop.take();
! message.equals("DONE");
message = drop.take()) {
System.out.format("MESSAGE RECEIVED: %s%n",
message);
Thread.sleep(random.nextInt(5000));
}
} catch (InterruptedException e) {}
}
}For
ProducerConsumerExample
, we simply change the declaration for thedrop
object:import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue; public class ProducerConsumerExample {
public static void main(String[] args) {
BlockingQueue<String> drop =
new SynchronousQueue<String> ();
(new Thread(new Producer(drop))).start();
(new Thread(new Consumer(drop))).start();
}
}
answer 就不翻了
^_^本系列终于翻译完结了^_^撒花^_^高兴^_^