0
点赞
收藏
分享

微信扫一扫

Java面试题:实现线程间通信和线程等待


目录

  • ​​一、两个线程同时执行​​
  • ​​二、一个线程去等待另一个线程​​
  • ​​三、两个线程交叉运行​​
  • ​​四、一个线程去等待多个线程​​
  • ​​五、多个线程之间互相等待​​
  • ​​六、主线程获取子线程执行结果​​

一、两个线程同时执行

需求:假设有两个线程,一个是线程 A,另一个是线程 B,两个线程分别依次打印 1-3 三个数字

实现代码

package com.example;

public class Demo {
public static void printNumbers(String threadName){
for (int i = 1; i <= 3; i++) {

try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println(threadName + ": " + i);
}
}

public static void main(String[] args) {
// 线程A
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
printNumbers("Thread A");
}
});

// 线程B
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
printNumbers("Thread B");
}
});

// 启动线程
threadA.start();
threadB.start();
}
}

输出结果

Thread B: 1
Thread A: 1
Thread B: 2
Thread A: 2
Thread B: 3
Thread A: 3

二、一个线程去等待另一个线程

需求: B 在 A 全部打印完后再开始打印

实现方法:使用​​thread.join()​

实现代码

package com.example;

public class Demo {
public static void printNumbers(String threadName){
for (int i = 1; i < 4; i++) {

try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println(threadName + ": " + i);
}
}
public static void main(String[] args) {
// 线程A
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
printNumbers("Thread A");
}
});

// 线程B
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("B 开始等待 A");

try {
threadA.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

printNumbers("Thread B");
}
});

// 启动线程
threadB.start();
threadA.start();
}
}

执行结果

B 开始等待 A
Thread A: 1
Thread A: 2
Thread A: 3
Thread B: 1
Thread B: 2
Thread B: 3

三、两个线程交叉运行

需求:A 在打印完 1 后,再让 B 打印 1, 2, 3,最后再回到 A 继续打印 2, 3。

实现方法:​​object.wait()​​​ 和 ​​object.notify()​

实现代码

package com.example;

public class Demo {
public static void main(String[] args) {
// 共享的对象锁
Object lock = new Object();

// 线程A
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Thread A 等待锁");

synchronized (lock) {
System.out.println("Thread A 得到了锁 lock");
System.out.println("Thread A 1");

try {
// 交出锁的控制权
System.out.println("Thread A 准备进入等待状态,放弃锁 lock 的控制权 ");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("Thread 有人唤醒了 A, A 重新获得锁 lock");
System.out.println("Thread A 2");
System.out.println("Thread A 3");
}
}
});

// 线程B
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Thread B 等待锁 ");
synchronized (lock) {

System.out.println("Thread B 得到了锁 lock");
System.out.println("Thread B 1");
System.out.println("Thread B 2");
System.out.println("Thread B 3");

System.out.println("Thread B 打印完毕,调用 notify 方法 ");
// 释放控制权
lock.notify();
}
}
});

// 启动线程
threadA.start();
threadB.start();
}
}

执行结果

Thread A 等待锁
Thread A 得到了锁 lock
Thread A 1
Thread A 准备进入等待状态,放弃锁 lock 的控制权
Thread B 等待锁
Thread B 得到了锁 lock
Thread B 1
Thread B 2
Thread B 3
Thread B 打印完毕,调用 notify 方法
Thread 有人唤醒了 A, A 重新获得锁 lock
Thread A 2
Thread A 3

四、一个线程去等待多个线程

需求:四个线程 A B C D,其中 D 要等到 A B C 全执行完毕后才执行,而且 A B C 是同步运行的

实现方式: ​​CountdownLatch​

实现代码

package com.example;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class Demo {
public static void main(String[] args) {
// 创建一个计数器
int worker = 3;
CountDownLatch countDownLatch = new CountDownLatch(worker);

// 线程
new Thread(new Runnable() {
@Override
public void run() {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("Thread D");
}
}).start();

List<String> threadNames = Arrays.asList("Thread A", "Thread B", "Thread C");
for (String threadName : threadNames) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(threadName);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}

countDownLatch.countDown();
}
}).start();
}
}
}

执行结果

Thread A
Thread C
Thread B
Thread D

五、多个线程之间互相等待

需求:线程 A B C 各自开始准备,直到三者都准备完毕,然后再同时运行

实现方式: ​​CyclicBarrier​

实现代码

package com.example;

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class Demo {
public static void main(String[] args) {
// 创建一个计数器
int worker = 3;
CyclicBarrier cyclicBarrier = new CyclicBarrier(worker);

final Random random = new Random();

List<String> threadNames = Arrays.asList("Thread A", "Thread B", "Thread C");
for (String threadName : threadNames) {
new Thread(new Runnable() {
@Override
public void run() {
int sleep = random.nextInt(1000) + 100;

System.out.println(threadName + " sleep: " + sleep);
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}

// 等待
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}

// 所有线程都准备好了,一起执行
System.out.println(threadName);

}
}).start();
}
}
}

执行结果

Thread A sleep: 989
Thread C sleep: 522
Thread B sleep: 1056
Thread B
Thread C
Thread A

六、主线程获取子线程执行结果

需求:子线程完成某件任务后,把得到的结果回传给主线程

实现方式: Callable + FutureTask

实现代码

package com.example;

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;

public class Demo {
public static void main(String[] args) {

// 计算0-100之和
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {

Thread.sleep(1000);

int result = 0;
for (int i = 0; i <= 100; i++) {
result += i;
}

return result;
}
};

// 启动子线程计算
FutureTask<Integer> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();

// 等待子线程结束,并获取计算结果
try {
Integer result = futureTask.get();
System.out.println("result: " + result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}

}
}

执行结果

result: 5050

参考
​​​面试官:Java 是如何实现线程间通信的?​​


举报

相关推荐

0 条评论