Java单例模式在多线程环境下的性能测试对比实验分析
来源:互联网 发布:大数据 书 编辑:程序博客网 时间:2024/05/16 05:49
Java设计模式之单例模式
单例模式顾名思义就是在内存只有一个实例,是一个比较常用的设计模式,在很多的应用场景都有使用。关于他的UML图,应用场景,优点和缺点我就不介绍了,可以参考别人的文章或者文献等。
实验目标:
- 验证几种单例模式是否线程安全
- 多线程条件下:传统技术实例化类的时间性能问题
- 多线程条件下:单例模式实例化类的时间性能问题
- 模拟场景进行实验的对比,用数据说话
单例模式模式之饿汉式 —线程安全
public class Singleton1{ private static final Singleton1 instance = new Singleton1(); /** * 构造函数设成私有,只允许获取实例的方法调用 */ private Singleton1(){ } public static Singleton1 getInstance(){ return instance; }}
验证是否饿汉式线程安全
public class Client { public static void main(String[] args) { // TODO Auto-generated method stub //开启100个线程获取对象实例 for(int i = 0;i<100;i++){ Person person = new Person(); person.start(); } } }/** * 模拟应用场景:例如:KTV房间里只有一个话筒:而且有很多人都要唱歌 多线程模拟多人拿起的话筒是不是一个话筒 */class Person extends Thread{ @Override public void run(){ System.out.println("话筒的hashCode值:"+Singleton1.getInstance().hashCode()); }}
结果如图所示
单利模式之懒汉模式 — 只做验证线程安全的那个
public class Singleton2 { private static Singleton2 instance = null; //构造函数私有 private Singleton2(){ } //静态的获取对象实例的方法 public static synchronized Singleton2 getInstance(){ if(instance == null){ instance = new Singleton2(); //如果对象为null则新建,否则直接返回 } return instance; }}
测试同上
单利模式之静态内部类
public class Singleton3 { private static class SingletonHolder{ private static final Singleton3 instance = new Singleton3(); } private Singleton3(){ } //静态的获取对象实例的方法 public static final Singleton3 getInstance(){ return SingletonHolder.instance; }}
验证结果:线程安全
单例模式之双重校验锁
public class Singleton4 { private volatile static Singleton4 instance; //构造 private Singleton4(){ } //静态的获取对象实例的方法 public static Singleton4 getInstance(){ // 两重判断, 第一重是为了避免不必要的同步,因为频繁的锁会降低系统的性能 // 第二重是在instance在null情况下才会创建实例 if(instance == null){ synchronized (Singleton4.class) { if(instance == null){ instance = new Singleton4(); } } } return instance; }}
测试结果:线程安全
单例模式之枚举:线程安全
public enum Singleton5 { INSTANCE;}
同理测试:结果线程安全
几种单例模式的时间消耗
package com.jinwen.singleton;import java.util.concurrent.CountDownLatch;public class Client { private static int count = 100; //规定的线程数 private static long jobCountPerThread = 1000L; //每个线程作业数 public static void main(String[] args) throws InterruptedException{ // TODO Auto-generated method stub test1(); // 饿汉式测试 test2(); //懒汉式 test3(); //静态内部类 test4(); //双重校验锁 test5(); //枚举 test6(); //在同一种情况下直接传统技术new一个对象出来 } /** * 饿汉式在多线程环境下的测试函数 */ public static void test1() throws InterruptedException{ long startTime = System.currentTimeMillis(); //开始时间 final CountDownLatch countDownLatch = new CountDownLatch(count); for(int i=0;i<count;i++){ new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < jobCountPerThread; i++) { Singleton1 s1 = Singleton1.getInstance(); } countDownLatch.countDown(); } }).start(); } countDownLatch.await(); long endTime = System.currentTimeMillis(); System.out.println("饿汉式总消耗时间:"+(endTime-startTime)+"ms"); } /** * 懒汉式 多线程环境下的测试 */ public static void test2() throws InterruptedException{ long startTime = System.currentTimeMillis(); //开始时间 final CountDownLatch countDownLatch = new CountDownLatch(count); for(int i=0;i<count;i++){ new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < jobCountPerThread; i++) { Singleton2 s2 = Singleton2.getInstance(); } countDownLatch.countDown(); } }).start(); } countDownLatch.await(); long endTime = System.currentTimeMillis(); System.out.println("懒汉式总消耗时间:"+(endTime-startTime)+"ms"); } /** * 静态内部类 多线程环境下的测试 */ public static void test3() throws InterruptedException{ long startTime = System.currentTimeMillis(); //开始时间 final CountDownLatch countDownLatch = new CountDownLatch(count); for(int i=0;i<count;i++){ new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < jobCountPerThread; i++) { Singleton3 s3 = Singleton3.getInstance(); } countDownLatch.countDown(); } }).start(); } countDownLatch.await(); long endTime = System.currentTimeMillis(); System.out.println("静态内部类总消耗时间:"+(endTime-startTime)+"ms"); } /** * 双重校验锁 多线程环境下的测试 */ public static void test4() throws InterruptedException{ long startTime = System.currentTimeMillis(); //开始时间 final CountDownLatch countDownLatch = new CountDownLatch(count); for(int i=0;i<count;i++){ new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < jobCountPerThread; i++) { Singleton4 s4 = Singleton4.getInstance(); } countDownLatch.countDown(); } }).start(); } countDownLatch.await(); long endTime = System.currentTimeMillis(); System.out.println("双重校验锁总消耗时间:"+(endTime-startTime)+"ms"); } /** * 枚举 多线程环境下的测试 */ public static void test5() throws InterruptedException{ long startTime = System.currentTimeMillis(); //开始时间 final CountDownLatch countDownLatch = new CountDownLatch(count); for(int i=0;i<count;i++){ new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < jobCountPerThread; i++) { Singleton5 s5 = Singleton5.INSTANCE; } countDownLatch.countDown(); } }).start(); } countDownLatch.await(); long endTime = System.currentTimeMillis(); System.out.println("枚举总消耗时间:"+(endTime-startTime)+"ms"); } /**********************多线程环境下直接new一个对象********************************/ public static void test6() throws InterruptedException{ long startTime = System.currentTimeMillis(); //开始时间 final CountDownLatch countDownLatch = new CountDownLatch(count); for(int i=0;i<count;i++){ new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < jobCountPerThread; i++) { Singleton s = new Singleton(); } countDownLatch.countDown(); } }).start(); } countDownLatch.await(); long endTime = System.currentTimeMillis(); System.out.println("传统技术直接new总的消耗时间:"+(endTime-startTime)+"ms"); }}class Singleton{ public Singleton(){ }}/** * 模拟应用场景:例如:KTV房间里只有一个话筒:而且有很多人都要唱歌 多线程模拟多人拿起的话筒是不是一个话筒 */class Person extends Thread{ @Override public void run(){ //System.out.println("话筒的hashCode值:"+Singleton5.INSTANCE.hashCode()); }}
测试结果:通过不断的调整的count和jobCountPerThread的数,通过不断的进行实验,相信大家应该获得和我相类似的结果
实验结果如下图所示:
结果分析:当在一个线程中调用对象实例的次数越多,也就是JobCountPerThread越大,使用单例模式显然更好,当然懒汉单例模式除外,当线程数高,JobCountPerThread不高,也就是我们在实际生活高并发的情况,单例模式不会比传统的新建对象的性能好,当高并发情况下,大部分单例模式甚至会更差些。
总结:我们在学习的时候应该实事求是,严谨求学,模式只有在适合的场景下用对了才会发挥出更好的性能,否则情况可能会更差。最后,我还是学生,希望能有大神多多给我一些意见,指出不对的地方。
代码的地址:https://github.com/jinchen92/DesignPattern
阅读全文
0 0
- Java单例模式在多线程环境下的性能测试对比实验分析
- c++单例模式在多线程环境下的安全性
- 【Java 单例模式】Java 单例模式在多线程环境中可能存在的问题
- Java设计模式(二):单例模式的5种实现方式,以及在多线程环境下5种创建单例模式的效率
- Java设计模式(二):单例模式的5种实现方式,以及在多线程环境下5种创建单例模式的效率
- Java 多线程下的单例模式
- Java 多线程下的单例模式
- Java 多线程下的单例模式
- Java 多线程下的单例模式
- Java 多线程下的单例模式
- Java 多线程下的单例模式
- Java 多线程下的单例模式
- Java 多线程下的单例模式
- Java 多线程下的单例模式
- Java单例模式在多线程环境中的实现
- Java单例模式在多线程环境中的实现
- Java 单例模式在多线程环境中的实现
- 多线程环境下使用的单例模式的实现
- FZU2268 Cutting Game(数学,规律)(第七届福建省大学生程序设计竞赛)
- spark--transform算子--mapPartitions
- 第七届福建省赛 【(5+2)/10】
- 发表在 Science 上的一种新聚类算法
- Crazy Learning for Day 18
- Java单例模式在多线程环境下的性能测试对比实验分析
- Leetcode 461. Hamming Distance
- 自定义View,自定义Switch样式
- GirdView的学习
- 《MNIST学习》读取数据
- Codeforces Round #423 (Div. 2) A&&B&& C
- 利用Bilibili的开源库ijkplayer实现视频直播
- 【Android日记】Mocky生成模拟接口,Postman模拟接口请求
- [LeetCode] 217. Contains Duplicate