多執行緒 實現高效多借口呼叫
阿新 • • 發佈:2020-07-23
正常情況下我們呼叫多借口,都會順序呼叫,也就是序列,如果藉口直接沒有任何關係,而序列執行消耗的時間,就是各個藉口直接呼叫的總和。而jdk其實給我們提供有返回值型別執行緒,可以解決這個問題。
測試基類:用於統計執行時間
import org.apache.commons.lang.StringUtils; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.rules.TestName; import org.junit.runner.RunWith; import org.springframework.test.context.junit4.SpringRunner; import com.ms.cloud.common.util.frame.SpObserver; @RunWith(SpringRunner.class) public class BaseTest { private Long starttime; @Rule public TestName junitClass= new TestName(); @Before public void before() { starttime = System.currentTimeMillis(); setDataSource(); System.out.println(junitClass.getMethodName() + "....................start...................."); } @After public void after() { double usedtime = (System.currentTimeMillis() - starttime) / 1000.0; System.out.println("耗時 " + usedtime + " ms"); System.out.println(junitClass.getMethodName() + "....................end...................."); } protected voidsetDataSource() { this.setDataSource(null, null); } protected void setDataSource(String city, String sourceType) { if (StringUtils.isEmpty(city)) { city = "sz"; } if (StringUtils.isEmpty(sourceType)) { sourceType = "PC"; } SpObserver.putSoruce(sourceType); SpObserver.putSp(city); } }
工具類,模擬使用者呼叫多借口。每個介面消耗幾秒鐘。。
import java.util.concurrent.TimeUnit; public class UserUtils { public static String getHead(String uid) throws InterruptedException { TimeUnit.SECONDS.sleep(2); return "【"+uid+"】的頭"; } public static String getFace(String uid)throws InterruptedException { TimeUnit.SECONDS.sleep(5); return "【"+uid+"】的臉"; } public static String getFoot(String uid) throws InterruptedException { TimeUnit.SECONDS.sleep(7); return "【"+uid+"】的腳"; } }
正常情況下我們執行程式如此:
普通人:
import org.junit.Test; public class MyGodTest extends BaseTest { @Test public void testDo() throws InterruptedException { String uid = "路人甲"; StringBuffer sb = new StringBuffer(); sb.append(UserUtils.getHead(uid)).append("\n"); sb.append(UserUtils.getFace(uid)).append("\n"); sb.append(UserUtils.getFoot(uid)).append("\n"); System.out.println("資訊為:\n" + sb.toString()); } }
直接串聯:執行結果耗時14+s
testDo....................start.................... 資訊為: 【路人甲】的頭 【路人甲】的臉 【路人甲】的腳
耗時 14.016 ms testDo....................end....................
老程式設計師:
開啟多執行緒,非同步模式。用執行緒池與不用都可以。。讓執行緒跑起來就行
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; import org.junit.Test; /** * @desc 採用執行緒方式 * @author 陳惟鮮 chenweixian * @date 2020年7月23日 下午1:00:23 * */ public class MyGodThreadTest extends BaseTest { /**用執行緒執行 * @throws InterruptedException * @throws ExecutionException */ @Test public void testDo() throws InterruptedException, ExecutionException { String uid = "路人甲"; StringBuffer sb = new StringBuffer(); Callable<String> headCallable = new Callable<String>() { @Override public String call() throws Exception { return UserUtils.getHead(uid); } }; Callable<String> faceCallable = new Callable<String>() { @Override public String call() throws Exception { return UserUtils.getFace(uid); } }; Callable<String> footCallable = new Callable<String>() { @Override public String call() throws Exception { return UserUtils.getFoot(uid); } }; // FutureTask<String> headFutureTask = new FutureTask<>(headCallable); FutureTask<String> faceFutureTask = new FutureTask<>(faceCallable); FutureTask<String> footFutureTask = new FutureTask<>(footCallable); // 執行方法,執行緒非同步執行 new Thread(headFutureTask).start(); new Thread(faceFutureTask).start(); new Thread(footFutureTask).start(); sb.append(headFutureTask.get()).append("\n"); sb.append(faceFutureTask.get()).append("\n"); sb.append(footFutureTask.get()).append("\n"); System.out.println("資訊為:\n" + sb.toString()); } /**用執行緒池執行 * @throws InterruptedException * @throws ExecutionException */ @Test public void testPoolDo() throws InterruptedException, ExecutionException { String uid = "路人甲"; StringBuffer sb = new StringBuffer(); Callable<String> headCallable = new Callable<String>() { @Override public String call() throws Exception { return UserUtils.getHead(uid); } }; Callable<String> faceCallable = new Callable<String>() { @Override public String call() throws Exception { return UserUtils.getFace(uid); } }; Callable<String> footCallable = new Callable<String>() { @Override public String call() throws Exception { return UserUtils.getFoot(uid); } }; // FutureTask<String> headFutureTask = new FutureTask<>(headCallable); FutureTask<String> faceFutureTask = new FutureTask<>(faceCallable); FutureTask<String> footFutureTask = new FutureTask<>(footCallable); // 執行方法,執行緒非同步執行 ExecutorService executor = Executors.newCachedThreadPool(); executor.submit(headFutureTask); executor.submit(faceFutureTask); executor.submit(footFutureTask); executor.shutdown(); sb.append(headFutureTask.get()).append("\n"); sb.append(faceFutureTask.get()).append("\n"); sb.append(footFutureTask.get()).append("\n"); System.out.println("執行緒池資訊為:\n" + sb.toString()); } }
執行結果:7+s
testPoolDo....................start.................... 執行緒池資訊為: 【路人甲】的頭 【路人甲】的臉 【路人甲】的腳 耗時 7.02 ms testPoolDo....................end....................
總結:
多學多看,多實踐,對工作有幫助。
核心部分如下
Callable<String> footCallable = new Callable<String>() { @Override public String call() throws Exception { return UserUtils.getFoot(uid); == 業務處理 } }; FutureTask<String> headFutureTask = new FutureTask<>(headCallable); new Thread(faceFutureTask).start(); ==執行程式 footFutureTask.get() ==得到響應結果