String.format、字符串拼接、StringBuffer性能對比: StringBuffer > 字符串拼接 > String.format。java
public class StringAppendMultiThread { public static void main(String[] args) { method1(100000000); } static String success_code = "0"; static byte splite = 0x01; private static void method1(long times) { String resultMsg = ""; long time1 = System.nanoTime(); for (long i = 0; i < times; i++) { resultMsg = String.format("ErrorCode=%s%cErrorMsg=心跳包接收成功%c", success_code, splite, splite); } long time2 = System.nanoTime(); System.out.println("StringFormat:" + (time2 - time1) / times + "ns"); long time3 = System.nanoTime(); for (long i = 0; i < times; i++) { resultMsg = "ErrorCode=" + success_code + splite + "ErrorMsg=心跳包接收成功" + splite; } long time4 = System.nanoTime(); System.out.println("String add:" + (time4 - time3) / times + "ns"); StringBuffer sb = null; long time5 = System.nanoTime(); for (long i = 0; i < times; i++) { sb = new StringBuffer(); resultMsg = sb.append("ErrorCode=").append(success_code).append(splite).append("ErrorMsg=心跳包接收成功") .append(splite).toString(); } long time6 = System.nanoTime(); System.out.println("StringBuffer add:" + (time6 - time5) / times + "ns"); System.out.println("-------------------------------------------------"); } }
native方法,內部使用了jvm鎖。在併發狀況下,性能低下,且在windows與linux系統下性能表現一不樣,在Linux系統下運行性能更慢,與操做系統底層運行機制有關。linux
public class SystemCurrentTimeMultiThread { public static void main(String[] args) { for (int i = 0; i < 10; i++) { new Thread() { @Override public void run() { test_milli_speed(); } }.start(); } } static void test_milli_speed() { long sum = 0; int N = 100000000; long t1 = System.currentTimeMillis(); for (int i = 0; i < N; i++) sum += System.currentTimeMillis(); long t2 = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName() + "=》Sum = " + sum + "; time = " + (t2 - t1) + "; or " + (t2 - t1) * 1.0E6 / N + " ns / iter"); } }
非線程安全,多線程共享同一SimpleDateFormat,併發時會出現問題。 Apache common-lang提供的DateFormatUtils.format方法比JDK提供的SimpleDataFormat.format性能高出 149.82%。 推薦使用ThreadLocal方式綁定SimpleDateFormat到每一個線程中,這樣性能較好。 整體性能對比: ThreadLocal方式 > DateFormatUtils.format > 每次建立SimpleDataFormat.format
apache
public class SimpleDataFormatPerfTest { private static final int circleNum = 10000000; private static String pattern = "yyyy-MM-dd HH:mm:ss"; private Executor testExecutor = Executors.newFixedThreadPool(64); private static ThreadLocal<SimpleDateFormat> simpleDateFormatProvider = new ThreadLocal<SimpleDateFormat>() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } }; public static void main(String[] args) { SimpleDataFormatPerfTest test = new SimpleDataFormatPerfTest(); SimpleDateFormat format = new SimpleDateFormat(pattern); System.out.println("jdkSimpleDataFormat date format: " + format.format(new Date())); System.out.println("apacheSimpleDataFormat date format: " + DateFormatUtils.format(new Date(), pattern)); System.out.println( "threadLocalSimpleDataFormat date format: " + simpleDateFormatProvider.get().format(new Date())); // 1 Jdk SimpleDateFormat test.jdkSimpleDataFormatPerf(); // 2 Apache common-lang SimpleDateFormat test.apacheSimpleDataFormatPerf(); // 3 ThreadLocal SimpleDateFormat test.threadLocalSimpleDataFormatPerf(); } public void jdkSimpleDataFormatPerf() { long t1 = System.currentTimeMillis(); for (int i = 0; i < circleNum; i++) { SimpleDateFormat format = new SimpleDateFormat(pattern); format.format(new Date()); } long t2 = System.currentTimeMillis(); System.out.println("originSimpleDataFormat cost time: " + (t2 - t1)); } public void apacheSimpleDataFormatPerf() { long t1 = System.currentTimeMillis(); for (int i = 0; i < circleNum; i++) { DateFormatUtils.format(new Date(), pattern); } long t2 = System.currentTimeMillis(); System.out.println("apacheSimpleDataFormat cost time: " + (t2 - t1)); } public void threadLocalSimpleDataFormatPerf() { long t1 = System.currentTimeMillis(); for (int i = 0; i < circleNum; i++) { simpleDateFormatProvider.get().format(new Date()); } long t2 = System.currentTimeMillis(); System.out.println("threadLocalSimpleDataFormat cost time: " + (t2 - t1)); } }
ArrayList是一個非線程安全的集合類,底層數據結構是數組實現的,而數組是固定長度的,因此在ArrayList在添加元素時,若是數組長度不夠用時,須要擴張數組長度,而後再添加元素。在併發狀況下,會致使數據不正確。如下代碼示例:1000個線程,訪問同一個ArrayList對象,每一個線程往List中插入100個元素,最後,ArrayList中的元素個數並不是1000*100
,而會出現各類結果:99749,99453...。具體代碼以下:windows
package com.yss.sofa.demo.thread; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; public class ArralyListMultThread { public static void main(String[] args) { // 用來測試的ArrayList List<Object> list = new ArrayList<Object>(); // 線程數量(1000) int threadCount = 1000; // 用來讓主線程等待threadCount個子線程執行完畢 CountDownLatch countDownLatch = new CountDownLatch(threadCount); // 啓動threadCount個子線程 for (int i = 0; i < threadCount; i++) { Thread thread = new Thread(new MyThread(list, countDownLatch)); thread.start(); } try { // 主線程等待全部子線程執行完成,再向下執行 countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); } } class MyThread implements Runnable { List<Object> list; CountDownLatch countDownLatch; MyThread(List<Object> list, CountDownLatch countDownLatch) { this.list = list; this.countDownLatch = countDownLatch; } public void run() { for (int i = 0; i < 100; i++) { list.add(new Object()); } countDownLatch.countDown(); } }