java 多執行緒按順序執行、順序獲取結果
阿新 • • 發佈:2020-12-13
文章目錄
- 1、通過Thread的join方法
- 2、FutureTask
- 3、CountDownLatch(倒計數)
- 4、wait、notify
- 5、Condition(條件變數)
- 6、CyclicBarrier(迴環柵欄)
- 5、執行緒池
1、通過Thread的join方法
join主要是讓父執行緒等待子執行緒結束之後父執行緒才能繼續執行
public static void main(String[] args) throws InterruptedException { System.out.println("---開啟執行緒1---"); MyThread t1 = new MyThread("執行緒1"); t1.start(); t1.join(); System.out.println("---開啟執行緒2---"); MyThread t2 = new MyThread("執行緒2"); t2.start(); t2.join(); System.out.println("---開啟執行緒3---"); MyThread t3 = new MyThread("執行緒3"); t3.start(); t3.join(); } static class MyThread extends Thread { public MyThread(String name){ super(name); } @Override public void run() { super.run(); System.out.println(Thread.currentThread().getName()+"執行了"); } }
列印結果
---開啟執行緒1---
執行緒1執行了
---開啟執行緒2---
執行緒2執行了
---開啟執行緒3---
執行緒3執行了
2、FutureTask
public static void main(String[] args) throws InterruptedException, ExecutionException { System.out.println("---開啟執行緒1---"); FutureTask<String> f1 = new FutureTask<>(new MyCall()); Thread t1 = new Thread(f1,"執行緒1"); t1.start(); System.out.println("執行緒1返回結果: " + f1.get()); System.out.println("---開啟執行緒2---"); FutureTask<String> f2 = new FutureTask<>(new MyCall()); Thread t2 = new Thread(f2,"執行緒2"); t2.start(); System.out.println("執行緒2返回結果: " + f2.get()); System.out.println("---開啟執行緒3---"); FutureTask<String> f3 = new FutureTask<>(new MyCall()); Thread t3 = new Thread(f3,"執行緒3"); t3.start(); System.out.println("執行緒3返回結果: " + f3.get()); } static class MyCall implements Callable<String> { @Override public String call() throws Exception { return Thread.currentThread().getName(); } }
列印結果
---開啟執行緒1---
執行緒1返回結果: 執行緒1
---開啟執行緒2---
執行緒2返回結果: 執行緒2
---開啟執行緒3---
執行緒3返回結果: 執行緒3
3、CountDownLatch(倒計數)
現在有如下3個執行緒
public static void main(String[] args) throws InterruptedException, ExecutionException { System.out.println("---開啟執行緒1---"); Thread t1 = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(500); System.out.println("執行緒1執行了。。。"); } catch (InterruptedException e) { e.printStackTrace(); } } }, "執行緒1"); t1.start(); System.out.println("---開啟執行緒2---"); Thread t2 = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(200); System.out.println("執行緒2執行了。。。"); } catch (InterruptedException e) { e.printStackTrace(); } } }, "執行緒2"); t2.start(); System.out.println("---開啟執行緒3---"); Thread t3 = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(100); System.out.println("執行緒3執行了。。。"); } catch (InterruptedException e) { e.printStackTrace(); } } }, "執行緒3"); t3.start(); }
它們的執行結果是
---開啟執行緒1---
---開啟執行緒2---
---開啟執行緒3---
執行緒3執行了。。。
執行緒2執行了。。。
執行緒1執行了。。。
上面的輸出是按照3、2、1輸出的。如果現在要按照1、2、3的順序進行輸出,每個執行緒的sleep時間不能修改,該如何去處理?可以藉助CountDownLatch
private static CountDownLatch c1 = new CountDownLatch(1);
private static CountDownLatch c2 = new CountDownLatch(1);
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("---開啟執行緒1---");
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(500);
System.out.println("執行緒1執行了。。。");
c1.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "執行緒1");
t1.start();
System.out.println("---開啟執行緒2---");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
c1.await();
Thread.sleep(200);
System.out.println("執行緒2執行了。。。");
c2.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "執行緒2");
t2.start();
System.out.println("---開啟執行緒3---");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try {
c2.await();
Thread.sleep(100);
System.out.println("執行緒3執行了。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "執行緒3");
t3.start();
}
它們的執行結果是
---開啟執行緒1---
---開啟執行緒2---
---開啟執行緒3---
執行緒1執行了。。。
執行緒2執行了。。。
執行緒3執行了。。。
4、wait、notify
private final static Object lock1 = new Object();
private final static Object lock2 = new Object();
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("---開啟執行緒1---");
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock1) {
try {
lock1.wait();
Thread.sleep(500);
System.out.println("執行緒1執行了。。。");
lock1.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "執行緒1");
t1.start();
Thread.sleep(10);//這個主要保證執行緒開啟的順序
System.out.println("---開啟執行緒2---");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock1) {
try {
lock1.notify();
lock1.wait();
Thread.sleep(200);
System.out.println("執行緒2執行了。。。");
synchronized (lock2) {
lock2.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "執行緒2");
t2.start();
Thread.sleep(10);
System.out.println("---開啟執行緒3---");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock2) {
try {
lock2.wait();
Thread.sleep(100);
System.out.println("執行緒3執行了。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "執行緒3");
t3.start();
}
列印結果
---開啟執行緒1---
---開啟執行緒2---
---開啟執行緒3---
執行緒1執行了。。。
執行緒2執行了。。。
執行緒3執行了。。。
5、Condition(條件變數)
private static Lock lock = new ReentrantLock();
private static Condition condition1 = lock.newCondition();
private static Condition condition2 = lock.newCondition();
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("---開啟執行緒1---");
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
condition1.await();
Thread.sleep(500);
System.out.println("執行緒1執行了。。。");
condition1.signal();
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "執行緒1");
t1.start();
System.out.println("---開啟執行緒2---");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
condition1.signal();
condition1.await();
Thread.sleep(200);
System.out.println("執行緒2執行了。。。");
condition2.signal();
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "執行緒2");
t2.start();
System.out.println("---開啟執行緒3---");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
condition2.await();
Thread.sleep(100);
System.out.println("執行緒3執行了。。。");
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "執行緒3");
t3.start();
}
列印結果
---開啟執行緒1---
---開啟執行緒2---
---開啟執行緒3---
執行緒1執行了。。。
執行緒2執行了。。。
執行緒3執行了。。。
6、CyclicBarrier(迴環柵欄)
private static CyclicBarrier barrier1 = new CyclicBarrier(2);
private static CyclicBarrier barrier2 = new CyclicBarrier(2);
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("---開啟執行緒1---");
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(500);
System.out.println("執行緒1執行了。。。");
barrier1.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}, "執行緒1");
t1.start();
System.out.println("---開啟執行緒2---");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
barrier1.await();
Thread.sleep(200);
System.out.println("執行緒2執行了。。。");
barrier2.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}, "執行緒2");
t2.start();
System.out.println("---開啟執行緒3---");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try {
barrier2.await();
Thread.sleep(100);
System.out.println("執行緒3執行了。。。");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}, "執行緒3");
t3.start();
}
列印結果
---開啟執行緒1---
---開啟執行緒2---
---開啟執行緒3---
執行緒1執行了。。。
執行緒2執行了。。。
執行緒3執行了。。。
5、執行緒池
5.1、單執行緒化執行緒池
private static ExecutorService executorService = Executors.newSingleThreadExecutor();
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("---開啟執行緒1---");
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(500);
System.out.println("執行緒1執行了。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "執行緒1");
System.out.println("---開啟執行緒2---");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(200);
System.out.println("執行緒2執行了。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "執行緒2");
System.out.println("---開啟執行緒3---");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(100);
System.out.println("執行緒3執行了。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "執行緒3");
executorService.submit(t1);
executorService.submit(t2);
executorService.submit(t3);
}
列印結果
---開啟執行緒1---
---開啟執行緒2---
---開啟執行緒3---
執行緒1執行了。。。
執行緒2執行了。。。
執行緒3執行了。。。
5.2、多執行緒化執行緒池
其實最常見的還是使用多執行緒化的執行緒池去實現。
private static ExecutorService executorService = Executors.newFixedThreadPool(3);
public static void main(String[] args) throws InterruptedException, ExecutionException {
long start = System.currentTimeMillis();
ArrayList<Future<String>> futureList = new ArrayList<Future<String>>();
ArrayList<String> names = new ArrayList<String>();
for (int i = 0; i < 3; i++) {
futureList.add(executorService.submit(new MyCall(i + "")));
}
for (int i = 0; i < 3; i++) {
Future<String> future = futureList.get(i);
String value = future.get();
System.out.println("執行緒"+value+"執行了");
}
long spendTime = System.currentTimeMillis() - start;
System.out.println("花費時間---"+spendTime);
}
static class MyCall implements Callable<String> {
private String name;
public MyCall(String name) {
this.name = name;
}
@Override
public String call() throws Exception {
switch (name){
case "0":
Thread.sleep(3000);
break;
case "1":
Thread.sleep(2000);
break;
case "2":
Thread.sleep(1000);
break;
}
return name;
}
}
列印結果
執行緒0執行了
執行緒1執行了
執行緒2執行了
花費時間---3006
常見的問題:
- 1、2、3總共3個執行緒,按順序請求,按順序取結果。
- 1、2、3總共3個執行緒,執行緒3要等到執行緒1和2執行完才能執行,執行緒1和2是並行的。
- 寫一個多執行緒程式,交替輸出1,2,1,2,1,2
相信上面的問題應該不難了。。