仅总结目前已掌握的关于Java并发相关的知识点。
Part1, Basics
1, 多线程的作用,提高系统整体性能(IO Blocking,充分利用多核CPU)
2,Java如何实现多线程(继承 Thread,实现Runnable,实现Callable<E>)
3,Thread related methods(start,join,sleep,yield,interrupt,setDaemon,setPriority,setName,...)
4,多线程下如何保护临界资源(即线程互斥,引入问题示例:多个线程对计数器的累加)
可见性,有序性,内存模型(主内存,工作内存),volatile 和 synchronized 的使用,(读-读,写-读,写-写)
5,wait,notify,notifyall(线程同步),实现一个简单的BlockingQueue
6,ThreadLocal的使用,原理,为什么能解决临界资源访问冲突问题,HibernateSessionFactory
7,DeadLock,如何避免DeadLock,如何检查是否有DeadLock(jstack,jconsole,...)
Part2, Advanced
1,线程池的使用,能够解决什么问题(重复创建线程的开销,合理规划子任务并发执行的线程数量),
Executors.newFixedThreadPool(),
Executors.newCachedThreadPool(),
Executors.newScheduledThreadPool(),
Executors.newSingleThreadPool()
2,Future, FutureTask
Future: 获取线程执行结果,阻塞等待
FutureTask,对Runnable和Callable进行封装,阻塞等待
3,ReentrantLock,可重入,公平锁与非公平锁,使用格式(try-finally),时间锁等待,中断锁等待,CAS原语等
4,ReentrantReadWriteLock,使用场景及优点,实现自定义ConcurrentHashMap,读写分离
5,Condition的使用,优点,对BlockingQueue改写
6,Semaphore(信号量,停车场系统),CountDownLatch(确定所有子任何何时全部完成),CyclicBarrier(确定所有子任务同时开始,子任务需相互等待)
7,AtomicInteger,AtomicLong,累加器,不用手动加锁
8,synchronized与ReentrantLock的比较
synchronized:语言级别的支持,不用手动release锁对象,在一些简单环境下使用
ReentrantLock:非语言级别的支持,需手动release锁对象,使用更灵活(跨方法lock和unlock锁对象),功能更强大(时间锁等待,中断锁等待,公平和非公平锁,Condition的使用,读写锁的支持等),在synchronized无法满足需求的场景下使用
9,wait/notify/notifyAll与Condition的比较
wait/notify/notifyAll:任何对象都有的方法,用于简单场景下线程的同步,但控制粒度较粗(以锁对象为单位)
Condition:基于ReentrantLock锁对象创建的条件对象,用于复杂场景下线程的同步,能自定义控制粒度,更灵活
相关示例,某些示例需要在debug模式下结合断点运行,
package com.my.study.concurrent;
public class TestAddNumber {
private static long num = 0;
public static void main(String[] args) {
Thread t1 = new Thread(new SubClass());
Thread t2 = new Thread(new SubClass());
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num = " + num);
}
private static class SubClass implements Runnable {
@Override
public void run() {
//synchronized (TestAddNumber.class) {
for (long i = 1; i <= 100000000; i++) {
num += i;
}
//}
}
}
}
package com.my.study.concurrent;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
public class TestAtomic {
public static void main(String[] args) {
testAtomicInteger();
// testAtomicLong();
}
private static void testAtomicInteger() {
AtomicInteger ai = new AtomicInteger();
for (int i = 0; i < 10; i++) {
System.out.println(ai.getAndIncrement());
}
}
private static void testAtomicLong() {
AtomicLong al = new AtomicLong();
for (int i = 0; i < 10; i++) {
System.out.println(al.getAndIncrement());
}
}
}
package com.my.study.concurrent;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestCallable {
private static ExecutorService service = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
testStartCallableThread();
// testStartMultiCallableThread();
service.shutdown();
}
private static void testStartCallableThread() {
CallableClass clazz = new CallableClass(1);
Future<String> resultFuture = service.submit(clazz);
try {
System.out.println("Try to get result...");
String result = resultFuture.get();
System.out.println("Result is: " + result);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void testStartMultiCallableThread() {
List<Callable<String>> tasks = new ArrayList<Callable<String>>();
for (int i = 0; i < 5; i++) {
tasks.add(new CallableClass(i));
}
try {
List<Future<String>> results = service.invokeAll(tasks);
for (Future<String> result : results) {
System.out.println("Result is: " + result.get());
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static class CallableClass implements Callable<String> {
private int num;
public CallableClass(int num) {
this.num = num;
}
@Override
public String call() throws Exception {
try {
System.out.println("Begin call()." + num);
Thread.sleep(1000 * num);
System.out.println("End call()." + num);
return num + ",OK";
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
}
package com.my.study.concurrent;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class TestCondition {
private static MyBlockingQueue<Car> carQueue = new MyBlockingQueue<Car>(6);
public static void main(String[] args) {
Productor[] productors = new Productor[10];
for (int i = 0; i < productors.length; i++) {
productors[i] = new Productor("P" + i, carQueue);
}
for (Productor p : productors) {
new Thread(p).start();
}
Consumer[] consumers = new Consumer[1];
for (int i = 0; i < consumers.length; i++) {
consumers[i] = new Consumer("S" + i, carQueue);
}
for (Consumer c : consumers) {
new Thread(c).start();
}
}
private static class Productor implements Runnable {
private String productorName;
private MyBlockingQueue<Car> queue;
public Productor(String productorName, MyBlockingQueue<Car> queue) {
this.productorName = productorName;
this.queue = queue;
}
@Override
public void run() {
Car car = new Car(productorName + ": car");
queue.put(car);
System.out.println("Productor: " + productorName + ", car: "
+ car.getName());
}
}
private static class Consumer implements Runnable {
private String consumerName;
private MyBlockingQueue<Car> queue;
public Consumer(String consumerName, MyBlockingQueue<Car> queue) {
this.consumerName = consumerName;
this.queue = queue;
}
@Override
public void run() {
Car car = queue.take();
System.out.println("Consumer: " + consumerName + ", car: "
+ car.getName());
}
}
private static class Car {
private String name;
public Car(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
private static class MyBlockingQueue<E> {
private ReentrantLock lock = new ReentrantLock();
private Condition notEmpty = lock.newCondition();
private Condition notFull = lock.newCondition();
private List<E> elements = new LinkedList<E>();
private int capacity = 10;
public MyBlockingQueue(int capacity) {
if (capacity > 0 && capacity <= Integer.MAX_VALUE) {
this.capacity = capacity;
}
}
public void put(E e) {
lock.lock();
try {
while (capacity == elements.size()) {
try {
notFull.await();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
elements.add(e);
notEmpty.signalAll();
} finally {
lock.unlock();
}
}
public E take() {
lock.lock();
try {
while (elements.isEmpty()) {
try {
notEmpty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
E e = elements.remove(0);
notFull.signalAll();
return e;
} finally {
lock.unlock();
}
}
}
}
package com.my.study.concurrent;
import java.util.concurrent.CountDownLatch;
public class TestCountDownLatch {
private static CountDownLatch countDownLatch = new CountDownLatch(3);
public static void main(String[] args) {
Runnable r1 = new SubClass("Sub1", 1000 * 1);
Runnable r2 = new SubClass("Sub2", 1000 * 2);
Runnable r3 = new SubClass("Sub3", 1000 * 3);
new Thread(r1).start();
new Thread(r2).start();
new Thread(r3).start();
System.out.println("All threads has been started.");
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("CountDown finished.");
}
private static class SubClass implements Runnable {
private String name;
private long sleepTime;
public SubClass(String name, long sleepTime) {
this.name = name;
this.sleepTime = sleepTime;
}
@Override
public void run() {
System.out.println(name + ", begin run()");
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + ", end run()");
countDownLatch.countDown();
}
}
}
package com.my.study.concurrent;
import java.util.concurrent.CyclicBarrier;
public class TestCyclicBarrier {
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
public static void main(String[] args) {
Runnable r1 = new SubClass("Sub1", 1000 * 1);
Runnable r2 = new SubClass("Sub2", 1000 * 2);
Runnable r3 = new SubClass("Sub3", 1000 * 3);
new Thread(r1).start();
new Thread(r2).start();
new Thread(r3).start();
System.out.println("All threads has been started.");
}
private static class SubClass implements Runnable {
private String name;
private long sleepTime;
public SubClass(String name, long sleepTime) {
this.name = name;
this.sleepTime = sleepTime;
}
@Override
public void run() {
System.out.println(name + ", begin run()");
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(name + ", end run()");
}
}
}
package com.my.study.concurrent;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class TestFutureTask {
public static void main(String[] args) {
Runnable r = new SubClass();
String result = "This is result.";
FutureTask<String> ft = new FutureTask<String>(r, result);
new Thread(ft).start();
try {
String res = ft.get();
System.out.println("Result is: " + res);
} catch (Exception e) {
e.printStackTrace();
}
// No need to get result.
FutureTask<?> ft2 = new FutureTask<Void>(r, null);
new Thread(ft2).start();
try {
ft2.get();
} catch (Exception e) {
e.printStackTrace();
}
Callable<String> c = new SubClass2();
FutureTask<String> ft3 = new FutureTask<String>(c);
new Thread(ft3).start();
try {
String res = ft3.get();
System.out.println("Result is: " + res);
} catch (Exception e) {
e.printStackTrace();
}
}
private static class SubClass implements Runnable {
@Override
public void run() {
System.out.println("Begin SubClass.run()");
try {
Thread.sleep(1000 * 3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("End SubClass.run()");
}
}
private static class SubClass2 implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("Begin SubClass2.run()");
try {
Thread.sleep(1000 * 3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("End SubClass2.run()");
return "SubClass2.result";
}
}
}
package com.my.study.concurrent;
import java.util.concurrent.locks.ReentrantLock;
public class TestReentrantLock {
public static void main(String[] args) {
Runnable subClass = new SubClass();
new Thread(subClass, "Thread1").start();
new Thread(subClass, "Thread2").start();
}
private static class SubClass implements Runnable {
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
prt();
}
private void prt() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName());
} finally {
lock.unlock();
}
}
}
}
package com.my.study.concurrent;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class TestReentrantReadWriteLock {
public static void main(String[] args) {
MyConcurrentHashMap<String, String> map = new MyConcurrentHashMap<String, String>();
Runnable writeTask1 = new WriteTask(map, "key1", "value1");
Runnable writeTask2 = new WriteTask(map, "key2", "value2");
Runnable readTask1 = new ReadTask(map, "key1");
Runnable readTask2 = new ReadTask(map, "key2");
Runnable readTask3 = new ReadTask(map, "key3");
new Thread(writeTask1).start();
new Thread(writeTask2).start();
new Thread(readTask1).start();
new Thread(readTask2).start();
new Thread(readTask3).start();
}
private static class ReadTask implements Runnable {
private MyConcurrentHashMap<String, String> map;
private String key;
public ReadTask(MyConcurrentHashMap<String, String> map, String key) {
this.map = map;
this.key = key;
}
@Override
public void run() {
if (map == null) {
System.out.println("map is null, cannot get value.");
return;
}
String value = map.get(key);
System.out.println("ReadTask, key is:" + key + ", value is:"
+ value);
}
}
private static class WriteTask implements Runnable {
private MyConcurrentHashMap<String, String> map;
private String key;
private String value;
public WriteTask(MyConcurrentHashMap<String, String> map, String key,
String value) {
this.map = map;
this.key = key;
this.value = value;
}
@Override
public void run() {
if (map == null) {
System.out.println("map is null, cannot put value.");
return;
}
map.put(key, value);
System.out.println("WriteTask, key is:" + key + ", value is:"
+ value);
}
}
}
class MyConcurrentHashMap<K, V> {
private Map<K, V> map = new HashMap<K, V>();
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private Lock readLock = lock.readLock();
private Lock writeLock = lock.writeLock();
public V put(K key, V value) {
writeLock.lock();
try {
map.put(key, value);
return value;
} finally {
writeLock.unlock();
}
}
public V get(K key) {
readLock.lock();
try {
return map.get(key);
} finally {
readLock.unlock();
}
}
public boolean containsKey(K key) {
readLock.lock();
try {
return map.containsKey(key);
} finally {
readLock.unlock();
}
}
public V remove(K key) {
writeLock.lock();
try {
return map.remove(key);
} finally {
writeLock.unlock();
}
}
}
package com.my.study.concurrent;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
public class TestSemaphore {
private static Semaphore carSemaphore = new Semaphore(3);
private static ExecutorService service = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
List<Car> tasks = new ArrayList<Car>();
for (int i = 0; i < 5; i++) {
tasks.add(new Car("C" + i, carSemaphore));
}
try {
List<Future<String>> futureList = service.invokeAll(tasks);
for (Future<String> f : futureList) {
System.out.println(f.get());
}
} catch (Exception e) {
e.printStackTrace();
}
service.shutdown();
}
private static class Car implements Callable<String> {
private String name;
private Semaphore semaphore;
public Car(String name, Semaphore semaphore) {
this.name = name;
this.semaphore = semaphore;
}
@Override
public String call() {
park();
try {
Thread.sleep(1000 * 3);
} catch (InterruptedException e) {
e.printStackTrace();
}
leave();
return "OK, " + name;
}
private void park() {
System.out.println("Trying to park, car: " + name);
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Park done, car: " + name);
}
private void leave() {
System.out.println("Trying to leave, car: " + name);
semaphore.release();
System.out.println("Leave done, car: " + name);
}
}
}
package com.my.study.concurrent;
public class TestSynchronized {
public static void main(String[] args) {
Runnable subClass = new SubClass();
Thread t1 = new Thread(subClass, "Thread1");
Thread t2 = new Thread(subClass, "Thread2");
t1.start();
try {
Thread.sleep(1000 * 1);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
private static class SubClass implements Runnable {
@Override
public void run() {
prt();
}
private synchronized void prt() {
System.out.println("Begin:" + Thread.currentThread().getName());
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("End:" + Thread.currentThread().getName());
}
}
}