参考视频:B站Java工程师 高并发与多线程网络编程 (完)
1、四种Singleton(单例模式)方式的优缺点在多线程的情况下
饿汉式
public class SingletonObject1 {
/*
* can't lazy load
* */
private static final SingletonObject1 instance = new SingletonObject1();
private SingletonObject1(){
}
public static SingletonObject1 getInstance(){
return instance;
}
}
懒加载引出的问题
public class SingletonObject2 {
private static SingletonObject2 instance;
private SingletonObject2(){
}
public static SingletonObject2 getInstance(){
if( null == instance)
instance = new SingletonObject2();
return SingletonObject2.instance;
}
}
解决办法,加个锁。但是会影响性能
public class SingletonObject3 {
private static SingletonObject3 instance;
private SingletonObject3(){
}
public synchronized static SingletonObject3 getInstance(){
if( null == instance)
instance = new SingletonObject3();
return SingletonObject3.instance;
}
}
doublecheck的方式
public class SingletonObject4 {
private static SingletonObject4 instance;
private SingletonObject4(){
}
//double check
public static SingletonObject4 getInstance(){
if( null == instance){
synchronized (SingletonObject4.class){
if(null == instance)
instance = new SingletonObject4();
}
}
return SingletonObject4.instance;
}
}
volatile不保证原子性,保证了可见性和有序性。
public class SingletonObject5 {
private static volatile SingletonObject5 instance;
private SingletonObject5(){
}
//double check
public static SingletonObject5 getInstance(){
if( null == instance){
synchronized (SingletonObject5.class){
if(null == instance)
instance = new SingletonObject5();
}
}
return SingletonObject5.instance;
}
}
内部类的方法
public class SingletonObject6 {
private SingletonObject6(){
}
private static class InstanceHolder{
private final static SingletonObject6 instance = new SingletonObject6();
}
public static SingletonObject6 getInstance() {
return InstanceHolder.instance;
}
}
枚举的方法
public class SingletonObject7 {
private SingletonObject7(){
}
private enum Singleton{
INSTANCE;
private final SingletonObject7 instance;
Singleton(){
instance = new SingletonObject7();
}
public SingletonObject7 getInstance(){
return instance;
}
}
public static SingletonObject7 getInstance(){
return Singleton.INSTANCE.getInstance();
}
public static void main(String[] args) {
IntStream.rangeClosed(1,100).forEach( i -> new Thread(String.valueOf(i)) {
@Override
public void run() {
System.out.println(SingletonObject7.getInstance());
}
}.start());
}
}
2、多线程的休息室waitSet详细介绍与知识点
public class WaitSet {
private static final Object LOCK = new Object();
private static void work(){
synchronized (LOCK){
System.out.println("Begin...");
try {
System.out.println("Thread will coming");
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread will out");
}
}
/**
* 1.所有的对象都会有一个wait set,用来存放调用了该对象wait方法之后进入block状态线程
* 2.线程notify之后不一定立即得到执行
* 3.线程从wait set中被唤醒的迅速不一定是FIFO。
* 4.线程被唤醒后,必须重新获取锁
*/
public static void main(String[] args) throws InterruptedException {
/*new Thread(){
@Override
public void run() {
work();
}
}.start();
Thread.sleep(1000);
synchronized (LOCK){
LOCK.notify();
}*/
IntStream.rangeClosed(1,10).forEach(i -> new Thread(String.valueOf(i)){
@Override
public void run() {
synchronized (LOCK){
try {
Optional.of(Thread.currentThread().getName() + " will come to wait set.").ifPresent(System.out::println);
LOCK.wait();
Optional.of(Thread.currentThread().getName() + " will leave to wait set.").ifPresent(System.out::println);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start());
Thread.sleep(3000);
IntStream.rangeClosed(1,10).forEach(i ->
{
synchronized (LOCK){
LOCK.notify();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
);
}
}
3、一个解释volatile关键字作用最好的例子
public class VolatileTest {
private volatile static int INIT_VALUE = 0;
//private static int INIT_VALUE = 0;
private final static int MAX_LIMIT = 5;
public static void main(String[] args) {
new Thread( () -> {
int localValue = INIT_VALUE;
while (localValue < 5){
if(localValue != INIT_VALUE){
System.out.printf("The value updated to [%d]\n",INIT_VALUE);
localValue = INIT_VALUE;
}
}
}, "READ").start();
new Thread( () -> {
int localValue = INIT_VALUE;
while (INIT_VALUE < MAX_LIMIT) {
System.out.printf("Update the value to [%d]\n", ++localValue);
INIT_VALUE = localValue;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"UPDATE").start();
}
}
4、java内存模型以及CPU缓存不一致问题的引入
在下面的例子中,没有使用volatile关键字。没有出现最初的问题的原因是因为有++
这个写入的操作
public class VolatileTest2 {
//private volatile static int INIT_VALUE = 0;
private static int INIT_VALUE = 0;
private final static int MAX_LIMIT = 50;
public static void main(String[] args) {
new Thread( () -> {
while (INIT_VALUE < MAX_LIMIT){
System.out.println("T1 -> " + (++INIT_VALUE));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "ADDER-1").start();
new Thread( () -> {
while (INIT_VALUE < MAX_LIMIT) {
System.out.println("T2 -> " + (++INIT_VALUE));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"ADDER-2").start();
}
}
5、CPU及CPU缓存的结构,解决高速缓存一致性问题的两种解决办法
- 给数据总线枷锁
- CPU高速缓存协议
6、并发编程的三个重要概念:原子性、可见性、有序性
- 原子性:即一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。在java中对基本数据类型的变量读取和赋值是保证了原子性的,要么都成功,要么都失败,不可以终端。
- 可见性:可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。使用volatile关键字可以保证可见性
- 有序性:即程序执行的顺序按照代码的先后顺序执行。
happens - before relationship
1.代码的执行顺序,编写在前面的发生在编写在后面的
2.unlock必须发生在lock之后
3.volatile修饰的变量,对一个变量的写操作先于对该变量的读操作
4.线程的启动规则,start方法肯定先于线程run
5.线程的中断规则,interrupt这个动作必须发生在捕获该动作之前
6.线程的传递规则,操作A先于B,B先于C,那么A肯定先于C
7.对象的销毁规则,初始化必须发生在finalize之前
8.线程的终结规则,所有的操作都发生在线程死亡之前
7、volatile关键字深入理解
一旦一个共享变量被volatile修饰有两层语义
- 保证了不同线程间的可见性
- 禁止对其进行重排序,也就保证了有序性
- 并未保证原子性
Volatile关键字
- 保证重排序的是不会把后面的指令放到屏障的前面,也不会把前面的放到后面
- 强制对缓存的修改操作立刻写入主存
- 如果是写操作,他会导致其他CPU中的缓存失效
8、volatile关键字总结
Volatile的使用场景
- 状态量标记
volatile boolean start = true; while(start){ // } void close(){ start = flase; }
- 屏障前后的一致性
volatile boolean init; ---------Thread - 1------------- //................... obj = createobj(); init = true; ---------Thread - 2------------- while(!init){ sleep(); } useobj(obj);
9、观察者设计模式
public abstract class Observer {
protected Subject subject;
public Observer(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
public abstract void update();
}
public class Subject {
private List<Observer> obsevers = new ArrayList<>();
private int state;
public int getState(){
return this.state;
}
public void attach(Observer obsever){
obsevers.add(obsever);
}
public void setState(int state){
if(state == this.state){
return;
}
this.state = state;
notifyAllObsever();
}
public void notifyAllObsever(){
obsevers.stream().forEach(Observer::update);
}
}
public class BinaryObserver extends Observer {
public BinaryObserver(Subject subject){
super(subject);
}
@Override
public void update() {
System.out.println("Binary String:" + Integer.toBinaryString(subject.getState()));
}
}
public class OctalObserver extends Observer {
public OctalObserver(Subject subject) {
super(subject);
}
@Override
public void update() {
System.out.println("Octal String:" + Integer.toOctalString(subject.getState()));
}
}
public class ObserverClient {
public static void main(String[] args) {
final Subject subject = new Subject();
new BinaryObserver(subject);
new OctalObserver(subject);
System.out.println("======================");
subject.setState(10);
System.out.println("======================");
subject.setState(10);
System.out.println("======================");
subject.setState(15);
}
}
10、使用观察者设计模式观察线程的生命周期
public abstract class ObserverRunnable implements Runnable {
final protected LifeCycleListener listener;
public ObserverRunnable(LifeCycleListener listener) {
this.listener = listener;
}
protected void notifyChange(final RunnableEvent event){
listener.onEvent(event);
}
public enum RunnableState {
RUUING, ERROR, DONE
}
public static class RunnableEvent {
private final RunnableState state;
private final Thread thread;
private final Throwable cause;
public RunnableEvent(RunnableState state, Thread thread, Throwable cause) {
this.state = state;
this.thread = thread;
this.cause = cause;
}
public RunnableState getState() {
return state;
}
public Thread getThread() {
return thread;
}
public Throwable getCause() {
return cause;
}
}
}
public interface LifeCycleListener {
void onEvent(ObserverRunnable.RunnableEvent event);
}
public class ThreadLifeCycleObserver implements LifeCycleListener {
private final Object LOCK = new Object();
public void concurrentQuery(List<String> ids) {
if( ids == null || ids.isEmpty()){
return;
}
ids.stream().forEach(id -> new Thread(new ObserverRunnable(this) {