內容正在完善中……線程池inghtml
ArrayList:數組實現,按下標訪問效率高(隨機訪問),增刪操做費事java
Victor:在ArrayList基礎上添加了線程安全特性,效率下降面試
LinkedList:雙向鏈表實現,增刪效率高,不支持下標訪問(隨機訪問),只能順序查找express
HashSet:哈希表實現,查找效率高 O(1),無序ubuntu
LinkedHashSet:雙向鏈表維護元素的插入順序,查詢效率高,有序api
TreeSet:紅黑樹實現,有序( 甚至拿來排序orz ),查找效率較低 O(logN)數組
存值: put(K key, V value))
安全
經過key取value: get(K key)
,返回valuebash
取全部keys: keySet()
,返回key的集合併發
遍歷: (常考)
private static String keySetTest(HashMap<Integer, String> hashMap){
StringBuilder result = new StringBuilder("KeySetTest: ");
for ( Integer i : hashMap.keySet() ){
result.append(i).append(": ").append(hashMap.get(i));
}
return result.toString();
}
複製代碼
private static String entrySetTest(HashMap<Integer, String> hashMap){
StringBuilder result = new StringBuilder("EntrySetTest: ");
for ( Map.Entry<Integer, String> entry: hashMap.entrySet() ){
result.append(entry.getKey()).append(": ").append(entry.getValue());
}
return result.toString();
}
複製代碼
private static String iteratorTest(HashMap<Integer, String> hashMap){
StringBuilder result = new StringBuilder("IteratorTest: ");
Iterator iterator = hashMap.entrySet().iterator();
while( iterator.hasNext() ){
Map.Entry entry = (Map.Entry) iterator.next();
result.append(entry.getKey()).append(": ").append(entry.getValue());
}
return result.toString();
}
複製代碼
注意:經檢驗這就是EntrySet同樣的作法……idea會把此種方案視爲可優化爲foreach循環的可優化點
private static String foreachIteratorTest(HashMap<Integer, String> hashMap){
StringBuilder result = new StringBuilder("ForeachIteratorTest: ");
for ( Map.Entry<Integer, String> entry: hashMap.entrySet() ) {
result.append(entry.getKey()).append(": ").append(entry.getValue());
}
return result.toString();
}
複製代碼
private static String iteratorWithoutTypeTest(HashMap<Integer, String> hashMap){
StringBuilder result = new StringBuilder("IteratorWithoutTypeTest: ");
Iterator<Map.Entry<Integer, String>> iterator = hashMap.entrySet().iterator();
while( iterator.hasNext() ){
Map.Entry entry = iterator.next();
result.append(entry.getKey()).append(": ").append(entry.getValue());
}
return result.toString();
}
複製代碼
private static String foreachIteratorWithoutTypeTest(HashMap<Integer, String> hashMap){
StringBuilder result = new StringBuilder("ForeachIteratorWithoutTypeTest: ");
for (Map.Entry entry : hashMap.entrySet()) {
result.append(entry.getKey()).append(": ").append(entry.getValue());
}
return result.toString();
}
複製代碼
測速: 目前測速方案致使結果波動驗證,仍在調整中……
public static void main(String[] args){
HashMap<Integer, String> hashMap = new HashMap<>();
for (int i = 0; i < 1000000; i++) {
hashMap.put(i, String.valueOf(i));
}
for (int i = 1; i <= 6; i++) {
System.out.println(runTestWithClock(i, hashMap).substring(0, 30));
}
}
private static String runTestWithClock(int n, HashMap<Integer, String> hashMap){
String result = null;
long clock = System.currentTimeMillis();
long timer = 0;
System.out.println("--------"+n+"-------");
switch (n){
case 1:
result = keySetTest(hashMap);
break;
case 2:
result = entrySetTest(hashMap);
break;
case 3:
result = iteratorTest(hashMap);
break;
case 4:
result = foreachIteratorTest(hashMap);
break;
case 5:
result = coolerIteratorTest(hashMap);;
break;
case 6:
result = foreachCoolerIteratorTest(hashMap);
break;
}
timer = System.currentTimeMillis() - clock ;
System.out.println("Timer: "+timer);
return result;
}
複製代碼
--------1-------
Timer: 1232 1234 1207
KeySetTest: 0: 01: 12: 23: 34:
--------2-------
Timer: 96 112 100
EntrySetTest0: 01: 12: 23: 34:
--------3-------
Timer: 127 120 109
IteratorTest: 0: 01: 12: 23: 3
--------4-------
Timer: 98 91 111
ForeachIteratorTest: 0: 01: 12
--------5-------
Timer: 112 99 104
CoolerIteratorTest: 0: 01: 12:
--------6-------
Timer: 105 106 122
ForeachCoolerIteratorTest: 0:
複製代碼
method | 1 | 2 | 3 |
---|---|---|---|
KeySet | 1232 | 1234 | 1207 |
EntrySet | 96 | 112 | 100 |
Iterator | 127 | 120 | 109 |
ForeachIterator | 98 | 91 | 111 |
CoolerIterator | 112 | 99 | 104 |
ForeachCoolerIterator | 105 | 106 | 122 |
結果波動性比較大,安全起見從新制定測試計劃
先對①和②進行驗證
size | 2000k | 1500k | 1000k | 100k | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
times | 1 | 2 | 3 | 4 | 5 | 1 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 |
KeySet | 2315 | 2271 | 2303 | 2328 | 2258 | 813 | 816 | 819 | 1232 | 1234 | 1207 | 25 | 30 | 25 |
EntrySet | 203 | 1010 | 201 | 991 | 201 | 735 | 738 | 745 | 96 | 112 | 100 | 23 | 25 | 23 |
Iterator | 178 | 155 | 165 | 165 | 170 | 180 | 173 | 188 | 127 | 120 | 109 | 24 | 26 | 24 |
ForeachIterator | 986 | 147 | 983 | 194 | 971 | 138 | 134 | 137 | 98 | 91 | 111 | 27 | 27 | 37 |
IteratorWithoutType | 185 | 187 | 179 | 162 | 169 | 134 | 122 | 130 | 112 | 99 | 104 | 18 | 19 | 19 |
ForeachIteratorWithoutType | 183 | 188 | 180 | 156 | 150 | 145 | 112 | 121 | 105 | 106 | 122 | 19 | 21 | 20 |
表格渲染結果不佳,另附https://paste.ubuntu.com/p/VKmyxsGbdh/
由此表大體能夠認爲在這次測試中,HashMap<Integer,String>存儲簡單類型的k-v值:
猜測:
進一步推測:
驗證:
private static String entrySetTest(HashMap<Integer, String> hashMap) {
StringBuilder result = new StringBuilder("EntrySetTest: ");
Iterator var2 = hashMap.entrySet().iterator();
while(var2.hasNext()) {
Entry<Integer, String> entry = (Entry)var2.next();
result.append(entry.getKey()).append(": ").append((String)entry.getValue());
}
return result.toString();
}
複製代碼
private static String foreachIteratorTest(HashMap<Integer, String> hashMap) {
StringBuilder result = new StringBuilder("ForeachIteratorTest: ");
Iterator var2 = hashMap.entrySet().iterator();
while(var2.hasNext()) {
Entry<Integer, String> entry = (Entry)var2.next();
result.append(entry.getKey()).append(": ").append((String)entry.getValue());
}
return result.toString();
}
複製代碼
果真是同樣的,這些for-each是基於iterator實現的
結論:
public class RunnableThreadTest implements Runnable{
@Override
public void run() {
// do sth.
}
}
複製代碼
運行:
public static void main(String[] args) {
RunnableThreadTest threadTest = new RunnableThreadTest();
Thread thread = new Thread(threadTest);
thread.start();
}}
複製代碼
class ThreadTestExtentsThread extends Thread{
public static void main(String[] args) {
ThreadTestExtentsThread testExtentsThread = new ThreadTestExtentsThread();
testExtentsThread.start();
}
}
複製代碼
class CallableThreadTest implements Callable<Integer>{
@Override
public Integer call() throws Exception {
Integer result = 123;
// do sth.
return result;
}
}
複製代碼
使用:
public static void main(String[] args) throws ExecutionException, InterruptedException {
CallableThreadTest threadTest = new CallableThreadTest();
// 指派一項要完成的任務,目標得到物件類型爲Integer
FutureTask<Integer> task = new FutureTask<>(threadTest);
// 把task交託給thread
Thread thread007 = new Thread(task);
// 特工007開始執行任務:D (Target is locked)
thread007.start();
// 得到任務執行結果
Integer resultOfTask = task.get();
System.out.println(resultOfTask);
}
複製代碼
咳咳,使用007來理解FutureTask可能更清晰一些XD
唔,乾脆發揮一下神盾局AOS……
// 衆所周知神盾局致力於尋找o-8-4,隨叫隨到:D
class AOS implements Callable<O84>{
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 固然,這事兒運做得先有神盾局
AOS aos = new AOS();
// 還須要有任務
FutureTask<O84> mission = new FutureTask<>(aos);
// 任務須要指派特工去完成
Thread agent = new Thread(mission);
// 特工開始執行任務
agent.start();
/** 任務執行中 **/
// 獲取行動結果-o84
O84 target = mission.get();
System.out.println(target);
}
@Override
public O84 call() throws Exception {
O84 target = new O84();
// 行動中
// Find out what is o84
// Like Thor's hammer XD
return target;
}
}
class O84 {
private String name;
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}
複製代碼
這樣一想是否是清楚了不少咧:D (別趁如今回去看一次吼,時間瞬間……等等怎麼一天過去了)
new Thread(() -> {
// do sth.
}).start();
複製代碼
實際是用runnable的:
new Thread(new Runnable() {
@Override
public void run() {
// do sth.
}
}).start();
複製代碼
public class WaitNotifyTest {
private static Object goods = null;
private void waitNotify() throws InterruptedException {
new Thread(() -> {
synchronized (this){
while( goods == null ){
try{
System.out.println("1. [Consumer]Waiting");
this.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
System.out.println("3. [Consumer]Done");
}).start();
Thread.sleep(1000L);
new Thread(()->{
goods = new Object();
synchronized (this){
this.notifyAll();
System.out.println("2. [Consumer]NotifyAll");
}
}).start();
}
public static void main(String[] args) throws InterruptedException {
new WaitNotifyTest().waitNotify();
}
}
複製代碼
import java.util.concurrent.locks.LockSupport;
public class ParkUnparkTest {
private static Object goods = null;
public static void main(String[] args) throws InterruptedException {
new ParkUnparkTest().parkUnpark();
}
private void parkUnpark() throws InterruptedException {
Thread consumerThread = new Thread( ()->{
while( goods == null ){
System.out.println("1. [Consumer]Park");
LockSupport.park();
}
System.out.println("3. [Consumer]Done");
});
consumerThread.start();
Thread.sleep(1000L);
goods = new Object();
LockSupport.unpark(consumerThread);
System.out.println("2. [Consumer]Unpark");
}
}
複製代碼
測試類
public class ThreadPoolTest {
public static void main(String[] args) throws Exception {
ThreadPoolTest threadPoolTest = new ThreadPoolTest();
threadPoolTest.threadPoolExecutorTest01();
threadPoolTest.threadPoolExecutorTest02(); // 分別執行請自行添加註釋
threadPoolTest.threadPoolExecutorTest03();
}
private void submitMission(ThreadPoolExecutor threadPoolExecutor) throws Exception{
for (int i = 0; i < 15; i++) {
int n = i;
threadPoolExecutor.submit(() -> {
// 提交15項任務,每項需執行3秒
try{
System.out.println("Start: "+n);
Thread.sleep(3000L);
System.out.println("Finish: "+n);
}catch (InterruptedException e){
e.printStackTrace();
}
});
System.out.println("Submitted: "+i);
}
// 在提交完任務到任務執行完成之間,輸出線程池狀態
Thread.sleep(500L);
System.out.println("PoolSize: "+threadPoolExecutor.getPoolSize());
System.out.println("QueueSize: "+threadPoolExecutor.getQueue().size());
// 預期爲5項任務所有執行完成以後,輸出線程池狀態
Thread.sleep(15000L);
System.out.println("PoolSize: "+threadPoolExecutor.getPoolSize());
System.out.println("QueueSize: "+threadPoolExecutor.getQueue().size());
}
}
複製代碼
測試01代碼:
private void threadPoolExecutorTest01() throws Exception {
ThreadPoolExecutor tpe = new ThreadPoolExecutor(
5, // corePoolSize
10, // maximumPoolSize
5, // keepAliveTime
TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>());
submitMission(tpe);
}
複製代碼
測試01結果:
Submitted: 0
Start: 0
Submitted: 1
Submitted: 2
Start: 1
Submitted: 3
Start: 2
Submitted: 4 ← 5項任務提交
Start: 3
Start: 4 ← 5項任務啓動
Submitted: 5
Submitted: 6
Submitted: 7
Submitted: 8
Submitted: 9
Submitted: 10
Submitted: 11
Submitted: 12
Submitted: 13
Submitted: 14 ← 全部任務提交
PoolSize: 5 ← 池子中線程數
QueueSize: 10 ← 等待隊列中任務數量:10
Finish: 4
Finish: 1
Finish: 3
Finish: 0
Finish: 2 ← 5項任務結束
Start: 8
Start: 7
Start: 6
Start: 5
Start: 9 ← 後5項任務啓動
Finish: 7
Finish: 8
Finish: 5
Finish: 6
Finish: 9 ← 後5項任務結束
Start: 13
Start: 12
Start: 11
Start: 10
Start: 14 ← 最後5項任務啓動
Finish: 12
Finish: 13
Finish: 10
Finish: 14
Finish: 11 ← 最後5項任務結束
PoolSize: 5
QueueSize: 0 ← 等待隊列爲空
複製代碼
測試02代碼:
private void threadPoolExecutorTest02() throws Exception {
ThreadPoolExecutor tpe = new ThreadPoolExecutor(
5, // corePoolSize
10, // maximumPoolSize
5, // keepAliveTime
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) {
System.err.println("Mission rejected");
}
});
submitMission(tpe);
}
複製代碼
測試02結果:
Submitted: 0
Start: 0
Submitted: 1
Submitted: 2
Start: 1
Start: 2
Submitted: 3
Start: 3
Submitted: 4 ← 5項任務提交
Submitted: 5
Submitted: 6
Start: 4 ← 5項任務啓動
Submitted: 7
Submitted: 8
Submitted: 9
Start: 8
Submitted: 10
Start: 9
Submitted: 11
Start: 10
Submitted: 12 ← 等待隊列中任務數量:3
Start: 11
Mission rejected ← 此處提交數已經達到14>最大線程數10+等待隊列容量3,拒絕任務
Submitted: 13
Mission rejected ← 同理拒絕任務
Start: 12
Submitted: 14
PoolSize: 10 ← 已經達到池子最大線程數,可是核心仍是5
QueueSize: 3
Finish: 0
Finish: 4
Finish: 1
Finish: 3
Finish: 2 ← 核心數量5因此先執行5項任務
Start: 7 ← 開始取出等待隊列中的任務
Start: 5
Start: 6 ← 取完等待隊列中的任務
Finish: 10
Finish: 11
Finish: 9
Finish: 8
Finish: 12
Finish: 5
Finish: 7
Finish: 6 ← 執行結束,不包含任務14和15,他們被rejected了
複製代碼
以上兩則測試演示了ThreadPoolExecutor中池子最大線程數和等待隊列的效果,注意點:
簡圖:
等待隊列可視爲右方的蓄水箱,不設定大小則至關於無限積水,左側水箱maxSize永遠不會滿; 可是若是等待隊列有容量,左側水箱天然也就會出現溢出到maxSize的狀況(即num-capacity-corePoolSize需≤maximumPoolSize)
複製代碼