Java并发编程第二阶段

参考视频: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缓存的结构,解决高速缓存一致性问题的两种解决办法

  1. 给数据总线枷锁
  2. 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修饰有两层语义

  1. 保证了不同线程间的可见性
  2. 禁止对其进行重排序,也就保证了有序性
  3. 并未保证原子性

Volatile关键字

  1. 保证重排序的是不会把后面的指令放到屏障的前面,也不会把前面的放到后面
  2. 强制对缓存的修改操作立刻写入主存
  3. 如果是写操作,他会导致其他CPU中的缓存失效

8、volatile关键字总结

Volatile的使用场景

  1. 状态量标记
    volatile boolean start = true;  
    while(start){
           
        //  
    }  
    
    void close(){
           
        start = flase;  
    }   
    
  2. 屏障前后的一致性
    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) {
   
  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值