JUC并发编程学习

八锁机制

第一种以及第二种:锁的是方法调用者两个方法用的同一个锁

import java.util.concurrent.TimeUnit;

public class mulThread {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{
            phone.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone.call();
        },"B").start();
    }
}

class Phone{
    
 
    public synchronized void sendSms(){
        /*try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}

image-20200816150719740

先发短息,然后进行四秒等待,出现打电话

第三种,同步方法以及非同步方法

import java.util.concurrent.TimeUnit;

public class mulThread {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{
            phone.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone.hello();
        },"B").start();
    }

}

class Phone{
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
    public void hello(){
        System.out.printf("hello");
    }
}

先输入hello,等四秒输出短信

第四种:两个对象

import java.util.concurrent.TimeUnit;

public class mulThread {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone1 = new Phone();
        new Thread(()->{
            phone.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone1.call();
        },"B").start();
    }

}

class Phone{
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
    public void hello(){
        System.out.printf("hello");
    }
}

第五种:两个静态同步方法

import java.util.concurrent.TimeUnit;

public class mulThread {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone1 = new Phone();
        new Thread(()->{
            phone.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone.call();
        },"B").start();
    }

}

class Phone{
    //类已加载就处理static,锁的Class
    public static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public static synchronized void call(){
        System.out.println("打电话");
    }
    public void hello(){
        System.out.printf("hello");
    }
}

已经锁住class,所以只有一个锁

import java.util.concurrent.TimeUnit;

public class mulThread {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone1 = new Phone();
        new Thread(()->{
            phone.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone1.call();
        },"B").start();
    }

}

class Phone{
    public static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public static synchronized void call(){
        System.out.println("打电话");
    }
    public void hello(){
        System.out.printf("hello");
    }
}

一个对象,ji一个静态同步锁,普通同步锁

不是同一个锁

import java.util.concurrent.TimeUnit;

public class mulThread {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone1 = new Phone();
        new Thread(()->{
            phone.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone.call();
        },"B").start();
    }

}

class Phone{
    public static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public  synchronized void call(){
        System.out.println("打电话");
    }
    public void hello(){
        System.out.printf("hello");
    }
}

两个对象,一个静态同步锁,普通同步锁

import java.util.concurrent.TimeUnit;

public class mulThread {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone1 = new Phone();
        new Thread(()->{
            phone.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone1.call();
        },"B").start();
    }

}

class Phone{
    public static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public  synchronized void call(){
        System.out.println("打电话");
    }
    public void hello(){
        System.out.printf("hello");
    }
}

集合的不安全

list不安全

set不安全

hashMap不安全

callable

image-20200816170006761

代码测试:

package callabletest;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        new Thread().start();

        MyThread myThread = new MyThread();
        FutureTask task = new FutureTask(myThread);
        new Thread(task,"A").start();
        //get方法可能会造成阻塞
        Object o = task.get();
        System.out.println(o);


    }
}
class MyThread implements Callable{

    @Override
    public String call() throws Exception {
        return "null";
    }
}

辅助类

CountDownLatch

package add;


import java.util.concurrent.CountDownLatch;

public class count {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch count = new CountDownLatch(6);

        for (int i = 1; i <=6 ; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"out");
                count.countDown();
            }, String.valueOf(i)).start();

        }
        count.await();//等待归零,然后向下执行

        System.out.println("关门");
    }
}

原理:

count.countDown()

count.await();//等待归零,然后向下执行

每次又线程调用就减一,假设计数器变为0,countDownLatch。await()就会被唤醒,继续执行。

cycliBarrier

package add;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class adddemo {
    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
        CyclicBarrier barrier = new CyclicBarrier(7,()->{
            System.out.println("成功");
        });

        for (int i = 1; i <=7 ; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"show");
                try {
                    barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();

        }


    }
}

Semaphore

一个计数信号量

一般作用于限流

package add;



import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);

        for (int i = 1; i <=6 ; i++) {
            new Thread(()->{
                //acquire 得到
                //
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"抢到");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName()+"离开");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();
                }

            }, String.valueOf(i)).start();
        }
    }
}

原理:

semaphore.acquire();

semaphore.release();

ReadWriteLock

特点:读可以多线程进行,但是写只能一次

package rw;

import sun.font.FontRunIterator;

import java.time.temporal.ValueRange;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class demo {
    public static void main(String[] args) {
        Mycache mycache = new Mycache();
        for (int i = 1; i <=5 ; i++) {
            final int temp=i;
            new Thread(()->{
                mycache.put(temp+"",temp+"");
            },String.valueOf(temp)).start();
        }
        for (int i = 1; i <=5 ; i++) {
            final int temp=i;
            new Thread(()->{
                mycache.get(temp+"");
            },String.valueOf(temp)).start();
        }
    }

}
/*
自定义缓存
 */
class Mycache{
    private volatile Map<String,Object> map=new HashMap<>();
    private ReadWriteLock readWriteLock=new ReentrantReadWriteLock();

    //写的时候只希望同时只有一个线程写
    public void put(String key,Object v){
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"写入"+key);
            map.put(key, v);
            System.out.println(Thread.currentThread().getName()+"写入ok");
        } finally {
            readWriteLock.writeLock().unlock();
        }

    }
    public void get(String key){
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"读取"+key);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName()+"读取ok");
        } finally {
            readWriteLock.readLock().unlock();
        }


    }

}

阻塞队列

image-20200816220956341

测试:

package bq;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class Test {
    public static void main(String[] args) {
        test1();

    }

    /*
    抛出异常
     */
    public static void test1(){
        ArrayBlockingQueue queue = new ArrayBlockingQueue<>(3);
        System.out.println(queue.add("a"));
        System.out.println(queue.add("b"));
        System.out.println(queue.add("c"));
        System.out.println(queue.add("d"));
    }
}

会抛出异常

image-20200816221706827

package bq;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class Test {
    public static void main(String[] args) {
        test1();

    }

    /*
    抛出异常
     */
    public static void test1(){
        ArrayBlockingQueue queue = new ArrayBlockingQueue<>(3);
        System.out.println(queue.add("a"));
        System.out.println(queue.add("b"));
        System.out.println(queue.add("c"));
        System.out.println(queue.remove());
        System.out.println(queue.remove());
        System.out.println(queue.remove());
        System.out.println(queue.remove());

    }
}

image-20200816221911331

方式 抛出异常 有返回值,不抛异常 阻塞 等待 超时等待
添加 add offer put offer
移除 remove poll take poll
检查队首元素 element peek - -

SynchronusQueue

没有容量,只有取出来才能放进去下一个

测试:

package bq;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

public class Test {
    public static void main(String[] args) {
        BlockingQueue<String> objects = new SynchronousQueue<>();
        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName()+"put->1");
                objects.put("1");
                System.out.println(Thread.currentThread().getName()+"put->2");
                objects.put("2");
                System.out.println(Thread.currentThread().getName()+"put->3");
                objects.put("3");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try {

                System.out.println(Thread.currentThread().getName()+"-->"+objects.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+"-->"+objects.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+"-->"+objects.take());
                TimeUnit.SECONDS.sleep(3);

            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }).start();

    }
}

线程池

好处:

  1. 降低资源的消耗
  2. 提高响应的速度
  3. 方便管理

线程复用,可以控制最大的并发数,管理线程

三大方法

线程池不允许使用Excutors去创建,而是通过ThreadPoolExecutor的方式,这样的处理让更明确线程池的运行规则,规避资源耗尽的风险。

image-20200816225425448

package bq;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// Executors 工具类、3大方法
public class Pool {
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();// 单个线程
// ExecutorService threadPool = Executors.newFixedThreadPool(5); // 创建一个固定的线程池的大小
// ExecutorService threadPool = Executors.newCachedThreadPool(); // 可伸缩的,遇强则强,遇弱则弱
        try {
            for (int i = 0; i < 100; i++) {
// 使用了线程池之后,使用线程池来创建线程
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
// 线程池用完,程序结束,关闭线程池
            threadPool.shutdown();
        }
    }
}

七大参数

  public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
  public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
 public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

ThreadPoolExecutor

    public ThreadPoolExecutor(int corePoolSize,//核心线程数
                              int maximumPoolSize,//最大核心线程池大小
                              long keepAliveTime,//最大存活时间
                              TimeUnit unit,//超时单位
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,//阻塞队列
             Executors.defaultThreadFactory()//线程工厂
             , defaultHandler);//拒绝策略
    }

创建线程池

image-20200816230935368

image-20200816230942974

拒绝策略

image-20200816231127573

四大函数式编程

函数式接口:有且只有一个接口

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}
//简化编程模型,在新版本的信息底层

image-20200817103254131

代码测试:

Function

public class Fun {
    public static void main(String[] args) {
        Function function = new Function<String, String>() {
            @Override
            public String apply(String s) {
                return s;
            }
        };
        System.out.println(function.apply("abc"));
    }
}
@FunctionalInterface
public interface Function<T, R> {//传入t类型,返回R类型

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);

predicate断定型接口

//断定型接口:有一个输入参数,返回值只能是布尔值
public class predi {
    public static void main(String[] args) {
        Predicate<String> predicate = new Predicate<String>() {
            @Override
            public boolean test(String n) {
                return false;
            }
        };
    }
}

简化:

public class predi {
    public static void main(String[] args) {
        Predicate<String> predicate = (str)->{
            return str.isEmpty();
        };
        System.out.println(predicate.test(""));
    }
}

消费型接口consumer:只有输入,没有返回值

public class com {
    public static void main(String[] args) {
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String str) {
                System.out.println(str);
            }
        };
        consumer.accept("adsad");
    }
}

源码:

public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

Supplier供给型接口:没有参数,只有返回值

源码

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

测试:

public class sup {
    public static void main(String[] args) {
        Supplier syn=new Supplier() {
            @Override
            public String get() {
                return "null";
            }
        };
        System.out.println(syn.get());
    }
}

Stream流式计算

what?

测试:

package strem;

import org.omg.PortableServer.LIFESPAN_POLICY_ID;

import java.util.Arrays;
import java.util.List;

public class test {

    /*
    1.id为偶数
    2.年龄大于23
    3.大写字母
    4.倒着排序
    5,只有一个用户
     */
    public static void main(String[] args) {
        User a1 = new User(1, "A", 21);
        User a2 = new User(2, "B", 22);
        User a3 = new User(3, "C", 23);
        User a4 = new User(4, "D", 24);
        User a5 = new User(5, "E", 25);
        List<User> list= Arrays.asList(a1,a2,a3,a4,a5);
        //计算
        //链式编程
        list.stream()
                .filter(u-> u.getId()%2!=0)
                .filter(u->u.getAge()>=23)
                .map(u->u.getName().toLowerCase())
                .sorted((u,u11)->{return u11.compareTo(u);})
                .limit(1)
                .forEach(System.out::println);
    }
}
class User{
    private int id;
    private String name;
    private int age;

    public User(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

ForkJoin

what?

forkjoin在jdk1.7 并行执行任务,提高效率,大数据量

特点:工作窃取

异步回调

JMM

volatile

volatile是java虚拟机提供的轻量级的同步机制

  1. 保证可见性
  2. 不保证原子性
  3. 禁止指令重排

JMM

java内存模型,不存在的东西,概念,约定!

关于JMM的一些同步的约定:

1. 线程解锁前,必须把共享变量立刻

2. 

image-20200817115254396

 内存交互操作有8种,虚拟机实现必须保证每一个操作都是原子的,不可在分的(对于double和long类型的变量来说,load、store、read和write操作在某些平台上允许例外)

    • lock (锁定):作用于主内存的变量,把一个变量标识为线程独占状态
    • unlock (解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
    • read (读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用
    • load (载入):作用于工作内存的变量,它把read操作从主存中变量放入工作内存中
    • use (使用):作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机遇到一个需要使用到变量的值,就会使用到这个指令
    • assign (赋值):作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变量副本中
    • store (存储):作用于主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中,以便后续的write使用
    • write  (写入):作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中

 JMM对这八种指令的使用,制定了如下规则:

    • 不允许read和load、store和write操作之一单独出现。即使用了read必须load,使用了store必须write
    • 不允许线程丢弃他最近的assign操作,即工作变量的数据改变了之后,必须告知主存
    • 不允许一个线程将没有assign的数据从工作内存同步回主内存
    • 一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是怼变量实施use、store操作之前,必须经过assign和load操作
    • 一个变量同一时间只有一个线程能对其进行lock。多次lock后,必须执行相同次数的unlock才能解锁
    • 如果对一个变量进行lock操作,会清空所有工作内存中此变量的值,在执行引擎使用这个变量前,必须重新load或assign操作初始化变量的值
    • 如果一个变量没有被lock,就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量
    • 对一个变量进行unlock操作之前,必须把此变量同步回主内存

可见性

package demo;

import java.util.concurrent.TimeUnit;

public class JMM {
    private volatile static int num=0;
    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            while (num==0){

            }
        }).start();

        TimeUnit.SECONDS.sleep(2);
        num=1;
        System.out.println(num);
    }
}

可以保证可见性

不保证原子性

原子性:不可分割,线程A在执行任务的时候,不能被打扰的,也不能被分割,要么t同时失败,要么成功

如果不加lock和synchronized,可以使用什么?

可以使用原子类的包装类

image-20200817122355213

image-20200817122431249

这些类的底层都直接和操作系统挂勾,在内存中修改值,unsafe类是一个很特殊的存在。

指令重排

源代码-》编译器优化的重排-》指令并行也可能会重排-》内存系统也会重排-》执行。

volatile可以避免指令重排

内存屏障,cpu指令,作用:

​ 1.保证特点的操作的执行顺序

​ 2.可以保证某些变量的内存可见性

Volatile是可以保持可见性,不能保证原子性,由于内存屏障,可以保证避免指令重排现象。

单例模式

饿汉式

public class hungry {
    private hungry(){

    }
    private final static hungry HUNGRY=new hungry();

    public static hungry getInstance(){
        return HUNGRY;
    }
}

懒汉式

package model;

public class Lazy {
    private Lazy(){}
    private static Lazy lazy;

    public static Lazy getInstance(){
        if (lazy==null){
            lazy=new Lazy();
        }
        return lazy;
    }
}

普通懒汉式,在单线程的环境能够完美处理,但是在多线程的环境下,却不能保证。

双重检测模式的懒汉式 DCL懒汉式

package model;

public class Lazy {
    private Lazy(){}
    private volatile static Lazy lazy;

    public static Lazy getInstance(){
        if (lazy==null){
            synchronized (Lazy.class){
                if(lazy==null){
                    if(lazy==null){
                        lazy=new Lazy();//不是原子性操作
                    }
                }
            }

        }
        return lazy;
    }
}

反射可以破坏

package model;

import sun.applet.Main;

import javax.swing.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Lazy {
    private Lazy(){}
    private volatile static Lazy lazy;

    public static Lazy getInstance(){
        if (lazy==null){
            synchronized (Lazy.class){
                if(lazy==null){
                    if(lazy==null){
                        lazy=new Lazy();
                    }
                }
            }

        }
        return lazy;
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Lazy instance = Lazy.getInstance();
        Constructor<Lazy> constructor = Lazy.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        Lazy lazy1 = constructor.newInstance();
        System.out.println(instance.hashCode());
        System.out.println(lazy1.hashCode());
    }
}

解决方法:

构造方法加入

if(lazy!=null){
	throw new RuntimeException("error");
}

但是如果没有使用单例的模式创建,而是使用两次反射创建,则又会失效:

穿插静态内部类

package model;

public class Holder {
    private Holder(){}
    public static Holder getInstance(){
        return InnerClass.HOLDER;
    }
    public static class InnerClass{
        private static final Holder HOLDER=new Holder();
    }
}

为了解决反射破坏单例的情况,我们发现枚举可以保证唯一

枚举

package model;

import javax.sound.midi.Soundbank;

//enum本身也是一个类
public enum EnumSingle {

    INSTANCE;
    public EnumSingle getInstance(){
        return INSTANCE;
    }
}
class test{
    public static void main(String[] args) {
        EnumSingle instance = EnumSingle.INSTANCE;
        EnumSingle instance1 = EnumSingle.INSTANCE;
        System.out.println(instance==instance1);
    }
}

枚举的u源码

image-20200817134134997

CAS

posted @ 2020-09-06 18:36  且I听  阅读(77)  评论(0)    收藏  举报