博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java MD5 多线程环境下共享锁还是每次创建一个新的MessageDigest
阅读量:7279 次
发布时间:2019-06-29

本文共 5870 字,大约阅读时间需要 19 分钟。

hot3.png

在多线程环境下对字符串进行MD5,到底应该使用加锁来共享同一个MessageDigest呢?还是每次新创建一个,个人认为需要 根据程序运行的环境来分别对待。下边是从org.springframework.extensions.surf摘取的一段代码,实现了两种调用方式, 不过到底在何种情况下使用何种方式,目前还不是很清晰,希望通过测试能够得出结论。

Java代码  
  1. import java.security.MessageDigest;  
  2. import java.security.NoSuchAlgorithmException;  
  3.   
  4. /** 
  5.  *  The MD5 utility class computes the MD5 digest (aka: "hash") of a block 
  6.  *  of data; an MD5 digest is a 32-char ASCII string. 
  7.  * 
  8.  *  The synchronized/static function "Digest" is useful for situations where 
  9.  *  lock contention in the application is not expected to be an issue. 
  10.  * 
  11.  *  The unsynchronized/non-static method "digest" is useful in a 
  12.  *  multi-threaded program that wanted to avoid locking by creating 
  13.  *  an MD5 object for exclusive use by a single thread. 
  14.  * 
  15.  * 
  16.  *  
  17.  *  EXAMPLE 1:  Static usage 
  18.  * 
  19.  *      import org.springframework.extensions.surf.util.MD5; 
  20.  *      String x = MD5.Digest("hello".getBytes()); 
  21.  * 
  22.  * 
  23.  *  EXAMPLE 2:  Per-thread non-static usage 
  24.  * 
  25.  *      import org.springframework.extensions.surf.util.MD5; 
  26.  *      MD5 md5 = new MD5(); 
  27.  *      ... 
  28.  *      String x = md5.digest("hello".getBytes()); 
  29.  * 
  30.  *  
  31.  
  32. * Email: diwayou@163.com 
  33.  * User: diwayou 
  34.  * Date: 13-4-15 
  35.  * Time: 下午11:18 
  36.  */  
  37.   
  38. public class MD5 {  
  39.     private static final byte[] ToHex_ =  
  40.             { '0','1','2','3','4','5','6','7',  
  41.                     '8','9','a','b','c','d','e','f'  
  42.             };  
  43.   
  44.     private MessageDigest md5_ = null;  
  45.   
  46.     static private MessageDigest  Md5_;  
  47.     static  
  48.     {  
  49.         try { Md5_ = MessageDigest.getInstance("MD5");}  // MD5 is supported  
  50.         catch ( NoSuchAlgorithmException e ) {};         // safe to swallow  
  51.     };  
  52.   
  53.     /** 
  54.      *  Constructor for use with the unsynchronized/non-static method 
  55.      *  "digest" method.   Note that the "digest" function is not 
  56.      *  thread-safe, so if you want to use it, every thread must create 
  57.      *  its own MD5 instance.   If you don't want to bother & are willing 
  58.      *  to deal with the potential for lock contention, use the synchronized 
  59.      *  static "Digest" function instead of creating an instance via this 
  60.      *  constructor. 
  61.      */  
  62.     public MD5()  
  63.     {  
  64.         try { md5_ = MessageDigest.getInstance("MD5");}  // MD5 is supported  
  65.         catch ( NoSuchAlgorithmException e ) {};         // safe to swallow  
  66.     }  
  67.   
  68.     /** 
  69.      *   Thread-safe static digest (hashing) function. 
  70.      * 
  71.      *   If you want to avoid lock contention, create an instance of MD5 
  72.      *   per-thead, anc call the unsynchronized method 'digest' instead. 
  73.      */  
  74.     public static synchronized String Digest(byte[] dataToHash)  
  75.     {  
  76.         Md5_.update(dataToHash, 0, dataToHash.length);  
  77.         return HexStringFromBytes( Md5_.digest() );  
  78.     }  
  79.   
  80.     /** 
  81.      *  Non-threadsafe MD5 digest (hashing) function 
  82.      */  
  83.     public String digest(byte[] dataToHash)  
  84.     {  
  85.         md5_.update(dataToHash, 0, dataToHash.length);  
  86.         return HexStringFromBytes( md5_.digest() );  
  87.     }  
  88.   
  89.     private static String HexStringFromBytes(byte[] b)  
  90.     {  
  91.         byte [] hex_bytes = new byte[  b.length * 2 ];  
  92.         int i,j=0;  
  93.   
  94.         for (i=0; i < b.length; i++)  
  95.         {  
  96.             hex_bytes[j]   = ToHex_[ ( b[i] & 0x000000F0 ) >> 4 ] ;  
  97.             hex_bytes[j+1] = ToHex_[   b[i] & 0x0000000F ];  
  98.             j+=2;  
  99.         }  
  100.         return new String( hex_bytes );  
  101.     }  
  102. }  

 下边是闲暇时写的一段测试代码,测试方式考虑因素还是比较少的,只考虑到了竞争线程的数量,代码如下:

Java代码  
  1. package com.diwayou.logq;  
  2.   
  3. import com.diwayou.logq.util.MD5;  
  4. import org.jfree.chart.ChartFactory;  
  5. import org.jfree.chart.ChartFrame;  
  6. import org.jfree.chart.JFreeChart;  
  7. import org.jfree.chart.plot.PlotOrientation;  
  8. import org.jfree.data.xy.DefaultXYDataset;  
  9. import org.jfree.data.xy.XYDataset;  
  10.   
  11. import java.io.UnsupportedEncodingException;  
  12. import java.util.concurrent.ExecutorService;  
  13. import java.util.concurrent.Executors;  
  14.   
  15. /** 
  16.  * Email: diwayou@163.com 
  17.  * User: diwayou 
  18.  * Date: 13-3-26 
  19.  * Time: 下午5:48 
  20.  */  
  21. public class LogQ {  
  22.     public static void main(String[] args) throws UnsupportedEncodingException, InterruptedException {  
  23.         String s = "alibabagogogo";  
  24.         final byte[] message = s.getBytes("GBK");  
  25.         int coreNum = Runtime.getRuntime().availableProcessors();  
  26.         int scale = 100;  
  27.         System.out.println(String.format("Core size is %d", coreNum));  
  28.   
  29.         int TEST_TIMES = 1;  
  30.         long startTime, endTime;  
  31.         DefaultXYDataset xyDataset = new DefaultXYDataset();  
  32.         double[][] elapse = new double[2][scale];  
  33.         for (int j = 0; j < scale; j++) {  
  34.             ExecutorService executorService = Executors.newFixedThreadPool(scale);  
  35.             startTime = System.nanoTime();  
  36.             for (int i = 0; i < TEST_TIMES; i++) {  
  37.                 executorService.submit(new Runnable() {  
  38.   
  39.                     @Override  
  40.                     public void run() {  
  41.                         MD5.Digest(message);  
  42.                     }  
  43.                 });  
  44.             }  
  45.             executorService.shutdown();  
  46.             endTime = System.nanoTime();  
  47.             System.out.println(String.format("Pool size %d, elapse time %d", j, (endTime - startTime)));  
  48.   
  49.             elapse[0][j] = j;  
  50.             if (j == 0) {  
  51.                 elapse[1][j] = 0;  
  52.             } else {  
  53.                 elapse[1][j] = endTime - startTime;  
  54.             }  
  55.   
  56.         }  
  57.         xyDataset.addSeries("Synchronized", elapse);  
  58.   
  59.   
  60.         elapse = new double[2][scale];  
  61.         for (int j = 0; j < scale; j++) {  
  62.             ExecutorService executorService = Executors.newFixedThreadPool(scale);  
  63.             startTime = System.nanoTime();  
  64.             for (int i = 0; i < TEST_TIMES; i++) {  
  65.                 executorService.submit(new Runnable() {  
  66.   
  67.                     @Override  
  68.                     public void run() {  
  69.                         MD5 md5 = new MD5();  
  70.                         md5.digest(message);  
  71.                     }  
  72.                 });  
  73.             }  
  74.             executorService.shutdown();  
  75.             endTime = System.nanoTime();  
  76.             System.out.println(String.format("Pool size %d, elapse time %d", j, (endTime - startTime)));  
  77.             elapse[0][j] = j;  
  78.             if (j == 0) {  
  79.                 elapse[1][j] = 0;  
  80.             } else {  
  81.                 elapse[1][j] = endTime - startTime;  
  82.             }  
  83.         }  
  84.         xyDataset.addSeries("NewEveryTime", elapse);  
  85.         displayChart("Synchronized VS NewEveryTime", xyDataset);  
  86.     }  
  87.   
  88.     private static void displayChart(String title, XYDataset dataset) {  
  89.         JFreeChart xyLineChart = ChartFactory.createXYLineChart(title, "Pool Size""Elapse Time", dataset,  
  90.                 PlotOrientation.VERTICAL, truetruetrue);  
  91.         ChartFrame chartFrame = new ChartFrame("Stat Result", xyLineChart);  
  92.         chartFrame.pack();  
  93.         chartFrame.setVisible(true);  
  94.     }  
  95. }  

 运行结果如下:

(1)第一次
 Core size is 8Pool size 0, elapse time 2012874Pool size 1, elapse time 839776..............(2)第二次
 Core size is 8Pool size 0, elapse time 2256508Pool size 1, elapse time 795155Pool size 2, elapse time 968285...................结论:通过测试结果,可以看出每次都new一个新的并不比共享同一个MessageDigest慢,而且不需要锁,这样在服务器高并发的环境下,就不会出现共享锁性能瓶颈的问题,这样可以减少由于共享锁出现的上下文切换,个人倾向于每次都new一个。本人菜鸟一个,分析有误还请大家支出,随便批评,这样我才能进步。

转载于:https://my.oschina.net/diwayou/blog/125570

你可能感兴趣的文章
NPM酷库:winston 多路日志记录
查看>>
vue中的methods、computed和watch
查看>>
js 中的基本类型,引用类型,基本包装类型
查看>>
Word强大插件Writage使用手册
查看>>
CentOS7下PHP7.2安装redis扩展
查看>>
聊聊FilterSecurityInterceptor
查看>>
让数据库变快的10个建议
查看>>
Spring Boot 揭秘与实战
查看>>
【327天】跃迁之路——程序员高效学习方法论探索系列(实验阶段85-2017.12.29)...
查看>>
Redux 源码解析系列 -- Redux的实现思想
查看>>
数人云实录|微服务企业级落地将会带来哪些转变?
查看>>
[译]Flask教程--静态文件
查看>>
Laravel 大将之 View 模块
查看>>
Microsoft Graph:连接每个应用都需要的基础数据
查看>>
研究人员发现GPU侧道攻击漏洞
查看>>
解读 2018之Go语言篇(上):为什么Go语言越来越热?
查看>>
webpack 2 实践系列(一) — 安装与入门
查看>>
力荐!这些工具可以帮你写出干净的代码
查看>>
Chuck Cobb谈敏捷组织中PMO的角色
查看>>
Microsoft开源Visual Studio Test
查看>>