小白架构师成长之路18-并发编程定时线程池&DCL详解

并发编程定时线程池&DCL

大家里面的案例可以从gitHub下载下来自己看一下
地址:https://github.com/JolyouLu/Juc-study.git 代码在Juc-ScheduledExecutor下

定时线程池简介

之前我们讲的ThreadPoolExecutor是java的普通线程池。而ScheduledThreadPoolExecutor是java提供的定时任务线程池指定在某一个时间段运行指定代码。

常用方法

java.util.concurrent.ScheduledThreadPoolExecutor#schedule 延时任务java.util.concurrent.ScheduledThreadPoolExecutor#scheduleAtFixedRate 固定速率连续执行java.util.concurrent.ScheduledThreadPoolExecutor#scheduleWithFixedDelay非固定速率连续执行java.util.concurrent.ScheduledThreadPoolExecutor.DelayedWorkQueue延迟队列

schedule

schedule方法传入3个参数 Runnable(线程),delay(需要延时时间),TimeUnit(时间单位),让线程延时到指定时间后运行

public class ScheduledThreadPoolExecutorTest {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
        scheduledExecutorService.schedule(()->{
            System.out.println("延时任务:10秒后运行一次");
        },10, TimeUnit.SECONDS);
        scheduledExecutorService.schedule(()->{
            System.out.println("延时任务:3秒后运行一次");
        },3, TimeUnit.SECONDS);
    }
}

scheduleAtFixedRate

scheduleAtFixedRate 方法传入4个参数Runnable(线程),initialDelay(第一次运行需要延时的时间),delay(重复运行相距时间),TimeUnit(时间单位),让线程延时到指定时间后一直循环重复运行(不管你业务有没有执行完到达指定时间后执行任务)

public class ScheduledThreadPoolExecutorTest {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
        scheduledExecutorService.scheduleAtFixedRate(()->{
            System.out.println("定时任务:3秒跑一次");
        },0,2,TimeUnit.SECONDS);
    }
}

单列模式(Double check lock)

单列模式意思就是这个程序中永远都是只有这个对象,不会再new一个对象出来,但是在并发的情况下就可能会创建多个对象这个是我们不想的,以下有4种方法可以避免这类事情的发生

实现1

饿汉模式,字面意思理解,就是这段代码很饿,程序一初始化时候已经创建了这个对象,有用程序初始时就要创建对象会引起不必要的资源消耗。

//饿汉模式 线程安全 消耗资源
public class Singleton1 {

    private static Singleton1 singleton1 = new Singleton1();

    private Singleton1(){
    }

    public static Singleton1 getSingleton1(){
        return singleton1;
    }

    public static void main(String[] args) {
        for (int i = 0;i<100;i++){
            new Thread(()->{
                System.out.println(getSingleton1().hashCode());
            }).start();
        }
    }
}

实现2

懒汉模式,字面意思理解,就是这段代码很懒,等有人调用他的时候再初始化,由于创建对象时如果在并发状态下的不能保持单例,所以在创建对象前必须判断和加锁保证线程安全。

//懒汉模式 线程安全 使用双重检测
public class Singleton2 {
    private static volatile Singleton2 singleton2 = null;

    private Singleton2(){
    }

    public static Singleton2 getSingleton2(){
        if (null == singleton2){
            synchronized (Singleton2.class){
                if (null == singleton2){
                    singleton2 = new Singleton2();
                }
            }
        }
        return singleton2;
    }

    public static void main(String[] args) throws InterruptedException {
        final Set set;
        set = new CopyOnWriteArraySet();
        TlUtil.timeTasks(100, 1, new Runnable() {
            @Override
            public void run() {
                set.add(getSingleton2().hashCode());
            }
        });
        System.out.println(set.size());
    }
}

实现3

使用枚举类创建,因为枚举在jvm中只会被调用一次,所以可以确保线程安全,也是现在最推荐的用法。

//使用枚举方式 确保线程安全
public class Singleton3 {

    public Singleton3() {
    }
    private enum SingletonEnum{
        SINGLETON_ENUM;
        private Singleton3 singleton3;
        //jvm保证这个方法绝对的调用一次
        SingletonEnum(){singleton3 = new Singleton3();}
        public Singleton3 getSingleton3(){return singleton3;}
    }

    public static Singleton3 getSingleton3(){
        return SingletonEnum.SINGLETON_ENUM.getSingleton3();
    }

    public static void main(String[] args) {
        final Set set;
        set = new CopyOnWriteArraySet();
        for (int i = 0;i<100;i++){
            new Thread(()->{
                set.add(getSingleton3().hashCode());
            }).start();
        }
        System.out.println(set.size());
    }
}

实现4

//静态内部类实现线程安全的单例
public class Singleton4 {

    private Singleton4(){
    }
    private static class SingletonInner{
        private static final Singleton4 SINGLETON_4 = new Singleton4();
    }

    public static Singleton4 getSingleton4(){
        return SingletonInner.SINGLETON_4;
    }

    public static void main(String[] args) {
        final Set set;
        set = new CopyOnWriteArraySet();
        for (int i = 0;i<100;i++){
            new Thread(()->{
                set.add(getSingleton4().hashCode());
            }).start();
        }
        System.out.println(set.size());

    }

}

发布了33 篇原创文章 · 获赞 22 · 访问量 951

猜你喜欢

转载自blog.csdn.net/weixin_44642403/article/details/104574635