浅谈 SimpleDateFormat,第三方库joda-time,JDK8提供时间类 之性能和线程安全

简介: 浅谈 SimpleDateFormat,第三方库joda-time,JDK8提供时间类 之性能和线程安全

@[TOC]

一、java.text.SimpleDateFormat

java.text.SimpleDateFormat 的实例对象在多线程共享使用的时候会抛出转换异常,正确的使用方法应该是采用堆栈封闭,将其作为方法内的局部变量而不是全局变量,在每次调用方法的时候才去创建一个SimpleDateFormat实例对象,这样利用堆栈封闭就不会出现并发问题。

线程不安全,抛出异常写法:

package com.nobody.part02;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @author Mr.nobody
 * @Description
 * @date 2020/9/17
 */
public class SimpleDateFormatDemo {

    // 请求总数
    private static int CLIENT_COUNT = 10000;
    // 并发线程数
    private  static int THREAD_COUNT = 500;
    // 全局变量,多线程访问会线程不安全,抛异常
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");

    public static void main(String[] args) throws InterruptedException {
        // 固定线程池
        ExecutorService executorService = Executors.newFixedThreadPool(CLIENT_COUNT);
        // 控制同一个时刻,只能有多少个线程同时运行指定代码,即acquire和release之间的代码
        Semaphore semaphore = new Semaphore(THREAD_COUNT);
        CountDownLatch countDownLatch = new CountDownLatch(CLIENT_COUNT);
        for (int i = 0; i < CLIENT_COUNT; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    simpleDateFormat.parse("20200917");
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ParseException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        // 等待所有请求执行完
        countDownLatch.await();
        // 关闭线程池
        executorService.shutdown();
    }
}

在这里插入图片描述

线程安全写法:

package com.nobody.part02;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @author Mr.nobody
 * @Description
 * @date 2020/9/17
 */
public class SimpleDateFormatDemo {

    // 请求总数
    private static int CLIENT_COUNT = 10000;
    // 并发线程数
    private  static int THREAD_COUNT = 500;
    // 全局变量,多线程访问会线程不安全,抛异常
    //private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");

    public static void main(String[] args) throws InterruptedException {
        // 固定线程池
        ExecutorService executorService = Executors.newFixedThreadPool(CLIENT_COUNT);
        // 控制同一个时刻,只能有多少个线程同时运行指定代码,即acquire和release之间的代码
        Semaphore semaphore = new Semaphore(THREAD_COUNT);
        CountDownLatch countDownLatch = new CountDownLatch(CLIENT_COUNT);
        for (int i = 0; i < CLIENT_COUNT; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    // 局部变量,线程安全
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
                    simpleDateFormat.parse("20200917");
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ParseException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        // 等待所有请求执行完
        countDownLatch.await();
        // 关闭线程池
        executorService.shutdown();
    }
}

在这里插入图片描述

二、joda-time

第三方库 joda-time 的 DateTimeFormatter 类是线程安全的。
package com.nobody.part02;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @author Mr.nobody
 * @Description
 * @date 2020/9/17
 */
public class JodaTimeDemo {

    // 请求总数
    private static int CLIENT_COUNT = 10000;
    // 并发线程数
    private  static int THREAD_COUNT = 500;
    // 全局变量,线程安全
    private static DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyyMMdd");

    public static void main(String[] args) throws InterruptedException {
        // 固定线程池
        ExecutorService executorService = Executors.newFixedThreadPool(CLIENT_COUNT);
        // 控制同一个时刻,只能有多少个线程同时运行指定代码,即acquire和release之间的代码
        Semaphore semaphore = new Semaphore(THREAD_COUNT);
        CountDownLatch countDownLatch = new CountDownLatch(CLIENT_COUNT);
        for (int i = 0; i < CLIENT_COUNT; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    DateTime.parse("20200917", dateTimeFormatter).toDate();
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        // 等待所有请求执行完
        countDownLatch.await();
        // 关闭线程池
        executorService.shutdown();
    }
}

在这里插入图片描述

三、java.time.format.DateTimeFormatter

JDK8提供了许多不可变且线程安全的类,例如 java.time.LocalDate 、java.time.LocalTime,java.time.LocalDateTime 以及java.time.format.DateTimeFormatter等等。
package com.nobody.part02;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @author Mr.nobody
 * @Description
 * @date 2020/9/17
 */
public class JDK8TimeDemo {

    // 请求总数
    private static int CLIENT_COUNT = 10000;
    // 并发线程数
    private  static int THREAD_COUNT = 500;
    // 全局变量,JDK8时间类,线程安全
    private static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");

    public static void main(String[] args) throws InterruptedException {
        // 固定线程池
        ExecutorService executorService = Executors.newFixedThreadPool(CLIENT_COUNT);
        // 控制同一个时刻,只能有多少个线程同时运行指定代码,即acquire和release之间的代码
        Semaphore semaphore = new Semaphore(THREAD_COUNT);
        CountDownLatch countDownLatch = new CountDownLatch(CLIENT_COUNT);
        for (int i = 0; i < CLIENT_COUNT; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(LocalDate.parse("20200917", dateTimeFormatter));
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        // 等待所有请求执行完
        countDownLatch.await();
        // 关闭线程池
        executorService.shutdown();
    }
}

线程安全,正常输出
在这里插入图片描述

相关文章
|
2月前
|
Java Linux
java基础(3)安装好JDK后使用javac.exe编译java文件、java.exe运行编译好的类
本文介绍了如何在安装JDK后使用`javac.exe`编译Java文件,以及使用`java.exe`运行编译好的类文件。涵盖了JDK的安装、环境变量配置、编写Java程序、使用命令行编译和运行程序的步骤,并提供了解决中文乱码的方法。
51 2
|
1月前
lua面向对象(类)和lua协同线程与协同函数、Lua文件I/O
Lua的面向对象编程、协同线程与协同函数的概念和使用,以及Lua文件I/O操作的基本方法。
27 4
lua面向对象(类)和lua协同线程与协同函数、Lua文件I/O
|
14天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
13 3
|
14天前
|
Java
在Java多线程编程中,实现Runnable接口通常优于继承Thread类
【10月更文挑战第20天】在Java多线程编程中,实现Runnable接口通常优于继承Thread类。原因包括:1) Java只支持单继承,实现接口不受此限制;2) Runnable接口便于代码复用和线程池管理;3) 分离任务与线程,提高灵活性。因此,实现Runnable接口是更佳选择。
27 2
|
14天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
27 2
|
14天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
26 1
|
29天前
|
Dubbo Java 应用服务中间件
剖析Tomcat线程池与JDK线程池的区别和联系!
剖析Tomcat线程池与JDK线程池的区别和联系!
剖析Tomcat线程池与JDK线程池的区别和联系!
|
1月前
|
Java C++
【多线程】JUC的常见类,Callable接口,ReentranLock,Semaphore,CountDownLatch
【多线程】JUC的常见类,Callable接口,ReentranLock,Semaphore,CountDownLatch
32 0
|
2月前
|
缓存 Java 应用服务中间件
Java虚拟线程探究与性能解析
本文主要介绍了阿里云在Java-虚拟-线程任务中的新进展和技术细节。
|
14天前
|
监控 数据可视化 Java
如何使用JDK自带的监控工具JConsole来监控线程池的内存使用情况?
如何使用JDK自带的监控工具JConsole来监控线程池的内存使用情况?