文章目錄
- 1、通過Thread的join方法
- 2、FutureTask
- 3、CountDownLatch(倒計數)
- 4、wait、notify
- 5、Condition(條件變量)
- 6、CyclicBarrier(回環栅欄)
- 5、線程池
-
- 5.1、單線程化線程池
- 5.2、多線程化線程池
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
相信上面的問題應該不難了。。