1:概述:对于某些问题,能够并发的执行程序中的多个部分,则会变得非常方便甚至非常必要
2:并发的多面性:为了使程序运行的更快,你必须学会如何利用这些额外的处理器,而这正是并发赋予你的能力。从性能的角度来说,如果没有任务会被阻塞,那么在单处理器中使用并发就没有任何意义。
3: 定义任务:LiftOff
/**
* Created By Percy Gauguin On 2018/2/6
* 定义任务:线程可以驱动任务,因此需要顶一种描述任务的方式,这可以由Runnable接口提供
*/
public class LiftOff implements Runnable {
protected int countDown = 10;
private static int taskCount = 0;
private final int id = taskCount ++;
public LiftOff() {
}
public LiftOff(int countDown) {
this.countDown = countDown;
}
public String status() {
return "#" + id + "(" + (countDown > 0 ? countDown : "LiftOff!") + ")";
}
@Override
public void run() {
while (countDown -- > 0) {
System.out.println(status());
Thread.yield();
}
}
public static void main(String[] args) {
// 当Runnable接口中导出一个类时,其中的run()方法并无特殊之处,她不会产生任何内在的线程能力
// 要实现线程行为,必须显式地将一个任务附着到线程上,如...
LiftOff launch = new LiftOff();
launch.run();
// 如...
// 程序中会“同时”运行两个方法, main(), LiftOff.run() 是程序中与其他线程“同时”执行的代码。
// 所以会出现LiftOff.run() 还没有执行完,就打印waiting for liftoff。
Thread t = new Thread(new LiftOff());
t.start();
System.out.println("waiting for liftoff");
}
}
4:使用Executor执行器:CacheThreadPool
/**
* Created By Percy Gauguin On 2018/2/6
* java.util.concurrent包中的执行器(Executor)将为你管理Thread对象,从而简化并发编程。
*/
public class CacheThreadPool {
public static void main(String[] args) throws InterruptedException {
//ExecutorService es = Executors.newCachedThreadPool();
//ExecutorService es = Executors.newFixedThreadPool(5);
// SingleThreadExecutor就像是线程数量为1的FixedThreadPool。
// newSingleThreadExecutor会序列化所有提交给它的任务,并且维护自己的悬挂任务队列。
ExecutorService es = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
es.execute(new LiftOff());
}
TimeUnit.SECONDS.sleep(1
);
es.shutdown();
}
}
5:带返回值的任务 Callable<V>接口:TaskWithResult
public class TaskWithResult implements Callable<String> {
private int id;
public TaskWithResult(int id) {
this.id = id;
}
@Override
public String call() {
return "result of TaskWithResult " + id;
}
public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool();
List<Future<String>> futures = new ArrayList<Future<String>>();
for (int i = 0; i < 10; i++) {
// 这里使用的是submit()
futures.add(es.submit(new TaskWithResult(i)));
}
for (Future<String> fs : futures) {
try {
// get() blocks util completion
System.out.println(fs.get());
}
catch (InterruptedException e){
System.out.println(e);
return;
}
catch (ExecutionException e) {
System.out.println(e);
return;
}
finally {
es.shutdown();
}
}
}
}
6:最好把线程组看成是一次不成功的额尝试,你只要忽略它就好了。
7:解决共享资源竞争:读与写的同步。基本上所有的并发模式在解决线程冲突问题时,都是采用序列化共享资源的方案,这意味着在给定的时刻只允许一个任务访问共享资源。
lock包
8:可视性问题远比原子性问题复杂的多,一个任务做出的修改,即使在不中断的意义上是原子性的,对其他任务来说也可能是不可视的,(例如,修改知识暂时的存储在本地处理器的缓存中),因此不同的任务对应用的状态有不同的试图。同步机制强调在处理器系统中,一个任务做出的修改必须在应用中是可视的。volatile关键字可以保证应用中的可视性,如果将一个域声明为volatile的,那么只要对这个域产生了写操作,那么所有的读操作都可以看到这个修改,即使使用了本地缓存也是如此,volatile域会立即被写到主存中,而读取操作就发生在主存中。如果多个任务同时访问某个域,那么这个域应该是volatile的,否则,这个域就应该经由同步来访问,同步也会导致向主存中刷新,因此,如果一个域完全由synchronize方法或者语句块来防护,那就不需要将其设置volatile(所以不是很清楚volatile的作用。)
/**
* Created By Percy Gauguin On 2018/2/6
* volatile能保证所修饰域的可视性,但是不能保证线程安全
*/
public class SerialNumberGenerator {
// volatile不能对递增不是原子操作这一事实产生影响。
private static volatile int serialNumber = 0;
// note,this ++ operation is not thread-safe
// it will be thread-safe with synchronized
public static int nextSerialNumber() {
return serialNumber ++;
}
}
class CircularSet {
private int[] array;
private int len;
private int index = 0;
public CircularSet(int len) {
this.len = len;
array = new int[len];
// Initialize to a value not produced by the SerialNumberGenerator
for (int i = 0; i < len; i++) {
array[i] = -1;
}
}
public synchronized void add(int i) {
array[index] = i;
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 es = Executors.newCachedThreadPool();
static class SerialChecker implements Runnable {
@Override
public void run() {
while (true) {
int serial = SerialNumberGenerator.nextSerialNumber();
if (serials.contains(serial)) {
System.out.println("duplicate: " + serial);
System.exit(0);
}
serials.add(serial);
}
}
}
public static void main(String[] args) {
for (int i = 0; i < SIZE; i++) {
es.execute(new SerialChecker());
}
}
}
9:线程协作
/**
* Created By Percy Gauguin On 2018/2/7
* 线程协作
*/
class Car {
private boolean waxOn = false;
public synchronized void waxed() {
waxOn = true;
notifyAll();
}
public synchronized void buffed() {
waxOn = false; // ready for another coat or wax
notifyAll();
}
// buff完了之后调用,等待wax,不能继续buff
public synchronized void waitForWaxing() throws InterruptedException {
while (waxOn == false) {
wait();
}
}
// waxOn完了之后调用,等待buff,不能继续wax
public synchronized void waitForBuffing() throws InterruptedException {
while (waxOn == true) {
wait();
}
}
}
class WaxOn implements Runnable {
private Car car;
public WaxOn(Car car) {
this.car = car;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
System.out.println("wax on !");
TimeUnit.MILLISECONDS.sleep(200);
car.waxed();
car.waitForBuffing();
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class WaxOff implements Runnable {
private Car car;
public WaxOff(Car car) {
this.car = car;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
System.out.println("wax off !");
TimeUnit.MILLISECONDS.sleep(200);
car.buffed();
car.waitForWaxing();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class WaxOMatic {
public static void main(String[] args) throws InterruptedException {
Car car = new Car();
ExecutorService es = Executors.newCachedThreadPool();
es.execute(new WaxOn(car));
es.execute(new WaxOff(car));
TimeUnit.SECONDS.sleep(5);
es.shutdown();
}
}