两类线程:
生产者线程生产共享数据,消费者线程消费共享数据。
当共享数据满时,阻塞生产者继续生产数据放置入内;
当共享数据为空时,阻塞消费者继续消费数据。
1.使用Object的wait/notify的消息通知机制;
2.使用Lock的Condition的await/signal的消息通知机制。
注意点:1. while(条件判断) ,2. wait() / notifyAll() await() / signalAll()
模板:
// The standard idiom for calling the wait method in Java
synchronized (sharedObject) {
while (condition) {
sharedObject.wait();
// (Releases lock, and reacquires on wakeup)
}
// do action based upon condition e.g. take or put into queue
}
1.1 synchronized wait() / notifyAll() 代码:
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ProducerConsumer {
private static LinkedList<Integer> linkedList = new LinkedList<>();
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(15);
for (int i = 0; i < 5; i++) {
service.submit(new Producer(linkedList, 8));
}
for (int i = 0; i < 8; i++) {
service.submit(new Consumer(linkedList));
}
}
static class Producer implements Runnable {
private LinkedList<Integer> list;
private int maxLength;
public Producer(LinkedList<Integer> list, int maxLength) {
this.list = list;
this.maxLength = maxLength;
}
@Override
public void run() {
while (true) {
synchronized (list) {
try {
while (list.size() == maxLength) {
list.wait();
}
Random random = new Random();
int element = random.nextInt();
list.add(element);
System.out.println("Producer " + Thread.currentThread().getName() + " " + element);
list.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
static class Consumer implements Runnable {
private List<Integer> list;
public Consumer(List<Integer> list) {
this.list = list;
}
@Override
public void run() {
while (true) {
synchronized (list) {
try {
while (list.size() == 0) {
list.wait();
}
int element = list.remove(0);
System.out.println("Consumer " + Thread.currentThread().getName() + " " + element);
list.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
1.2 lock await() / signalAll() 代码
lock.lock
try{…
}catch(){
…业务代码
}finally{
lock.unlock()
}
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ProducerConsumer {
private static Lock lock = new ReentrantLock();
private static Condition full = lock.newCondition();
private static Condition empty = lock.newCondition();
public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
ExecutorService service = Executors.newFixedThreadPool(15);
for (int i = 0; i < 5; i++) {
service.submit(new Producer(list, 8, lock));
}
for (int i = 0; i < 10; i++) {
service.submit(new Consumer(list, lock));
}
}
static class Producer implements Runnable {
List<Integer> list;
int maxLength;
Lock lock;
public Producer(List list, int maxLength, Lock lock) {
this.list = list;
this.maxLength = maxLength;
this.lock = lock;
}
@Override
public void run() {
while (true) {
lock.lock();
try {
while (list.size() == maxLength) {
full.await();
}
Random random = new Random();
int element = random.nextInt();
list.add(element);
System.out.println("Producer " + Thread.currentThread().getName() + element);
empty.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
static class Consumer implements Runnable {
List<Integer> list;
Lock lock;
public Consumer(List<Integer> list, Lock lock) {
this.lock = lock;
this.list = list;
}
@Override
public void run() {
while (true) {
lock.lock();
try {
while (list.size() == 0) {
empty.await();
}
int element = list.remove(0);
System.out.println("Consumer " + Thread.currentThread().getName() + element);
full.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
}
Lock condition
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SequencePrint {
public static void main(String[] args) {
Data data = new Data();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data.printA();
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data.printB();
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data.printC();
}
}, "C").start();
}
}
class Data {
Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
int num = 1;
public void printA() {
lock.lock();
try {
while (num != 1) {
condition1.await();
}
num = 2;
System.out.println(Thread.currentThread().getName() +
"=> AAAAAAAAA");
condition2.signal();
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
while (num != 2) {
condition2.await();
}
num = 3;
System.out.println(Thread.currentThread().getName() +
"=> BBBBBBBBB");
condition3.signal();
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
while (num != 3) {
condition3.await();
}
num = 1;
System.out.println(Thread.currentThread().getName() +
"=> CCCCCCCCC");
condition1.signal();
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
A=> AAAAAAAAA
B=> BBBBBBBBB
C=> CCCCCCCCC
A=> AAAAAAAAA
B=> BBBBBBBBB
C=> CCCCCCCCC
A=> AAAAAAAAA
B=> BBBBBBBBB
C=> CCCCCCCCC
A=> AAAAAAAAA
B=> BBBBBBBBB
C=> CCCCCCCCC
A=> AAAAAAAAA
B=> BBBBBBBBB
C=> CCCCCCCCC
A=> AAAAAAAAA
B=> BBBBBBBBB
C=> CCCCCCCCC
A=> AAAAAAAAA
B=> BBBBBBBBB
C=> CCCCCCCCC
A=> AAAAAAAAA
B=> BBBBBBBBB
C=> CCCCCCCCC
A=> AAAAAAAAA
B=> BBBBBBBBB
C=> CCCCCCCCC
A=> AAAAAAAAA
B=> BBBBBBBBB
C=> CCCCCCCCC
// 问题1: 创建多个singleton
// 多个线程判断为null, 由于singleton没有被volatile修饰,
// 所以当一个线程已经new 了一个singleton, 其他线程不可见,
// 获得锁后,依然会new Singleton(); 创建多个singleton
// 问题2: 指令重排
// singleton = new Singleton();
// 三步: 分配内存空间; init初始化; singleton指向内存空间
// 指令重排 分配内存空间; singleton指向内存空间;init初始化
// 造成singleton != null, 但是没有初始化
// 所以会创建,没有初始化的单例对象
// 加在方法上又太笨重,获取和创建singleton都要阻塞等待。
public class LazyMan {
private LazyMan() {};
private static LazyMan singleton;
public static LazyMan getInstance() {
if(singleton == null) {
synchronized (LazyMan.class) {
singleton = new LazyMan();
}
}
return singleton;
}
}
双重校验null:
第一重:提高效率,获取线程不需要加锁,只有创建线程的时候加锁。
第二重:以前singleton没有加volatile时,多个线程进入代码,判断singleton为null, 其中一个线程获取锁,new单例对象,退出程序,释放锁。由于singleton对其他线程不可见,所以线程依然认为singleton为null, 又创建了一个单例对象。这里已经有了volatile,本不需要,安全起见,增加了null判断。
volatile: 禁止指令重排,因为已经有了第二层判断null, 所以这里的volatile主要作用是禁止指令重排。
public class DCLLazyMan {
private DCLLazyMan() {}
private volatile static DCLLazyMan singleton;
public static DCLLazyMan getInstance() {
if (singleton == null) {
synchronized (DCLLazyMan.class) {
if(singleton == null) {
singleton = new DCLLazyMan();
}
}
}
return singleton;
}
}
public class Hungry {
private Hungry() {}
private static final Hungry singleton = new Hungry();
public static Hungry getInstance() {
return singleton;
}
}
类加载时,new出来的单例对象,不会有线程安全的问题
public class Hungry {
private Hungry() {}
private static final Hungry singleton = new Hungry();
public static Hungry getInstance() {
return singleton;
}
}
延迟加载:加载Holder类时,不会加载其静态内部类,用到时才加载。
得到单例对象时,是加载静态内部类时,生成的单例对象,没有线程安全问题。
public class Holder {
private Holder() {}
public static class InnerClass {
private static final Holder HOLDER = new Holder();
}
public static Holder getInstance() {
return InnerClass.HOLDER;
}
}
枚举也是一个类,默认是单例的,且不允许通过反射创建枚举类对象,所以是最好的单例模式
public enum EnumSingleton {
INSTANCE;
public EnumSingleton getInstance() {
return INSTANCE;
}
}