经典面试题
下面是多线程顺序打印的经典面试题
1.三个线程分别打印 A,B,C,要求这三个线程一起运行,打印 n 次,输出形如“ABCABCABC…”的字符串
2.两个线程交替打印 0~100 的奇偶数
3.通过 N 个线程顺序循环打印从 0 至 100
4.多线程按顺序调用,A->B->C,AA 打印 5 次,BB 打印10 次,CC 打印 15 次,重复 10 次
5.用两个线程,一个输出字母,一个输出数字,交替输出 1A2B3C4D…26Z
6.利用两个线程,分别计算 0-n/2 和 n/2-n的和,然后返回和
思路:要么控制线程顺序,要么利用条件竞争锁
- public static void main(String[] args) {
-
- Semaphore s1 = new Semaphore(1);
- Semaphore s2 = new Semaphore(0);
- Semaphore s3 = new Semaphore(0);
-
- Thread t1 = new Thread(() -> {
- for (int i = 0; i < 10; i++) {
- try {
- s1.acquire();
- System.out.println("A");
- s2.release();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
-
- Thread t2 = new Thread(() -> {
- for (int i = 0; i < 10; i++) {
- try {
- s2.acquire();
- System.out.println("B");
- s3.release();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
-
- Thread t3 = new Thread(() -> {
- for (int i = 0; i < 10; i++) {
- try {
- s3.acquire();
- System.out.println("C");
- s1.release();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
- t1.start();
- t2.start();
- t3.start();
- }
第一题
- public static void test(int nums){
- Semaphore s1 = new Semaphore(1);
- Semaphore s2 = new Semaphore(0);
- AtomicInteger x = new AtomicInteger(0);
- Thread t1 = new Thread(() -> {
- try {
- for (int i = 0; i < nums/2; i++) {
- s1.acquire();
- System.out.println("线程1 " + x);
- x.getAndIncrement();
- s2.release();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- });
-
- Thread t2 = new Thread(() -> {
- try {
- for (int i = 0; i < nums/2; i++) {
- s2.acquire();
- System.out.println("线程2 " + x);
- x.getAndIncrement();
- s1.release();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- });
- t1.start();
- t2.start();
- }
第二题
- public class BBB {
- Object object = new Object();
- public int state;
- public int times;
-
- public BBB(int times) {
- this.times = times;
- }
-
- public void printABC(String name,int currentstate){
- for (int i = 0; i < times; i++)
- synchronized (object) {
- while (state % 3 != currentstate) {
- try {
- object.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- state++;
- System.out.print(name);
- object.notifyAll();
- }
- }
-
- public static void main(String[] args) {
- BBB bbb = new BBB(10);
- new Thread(()->{
- bbb.printABC("A",0);
- }).start();
- new Thread(()->{
- bbb.printABC("B",1);
- }).start();
- new Thread(()->{
- bbb.printABC("C",2);
- }).start();
- }
- }
第一题
思路:还是以第一题为例,我们用对象监视器来实现,通过 wait 和 notify() 方法来实现等待、通知的逻辑,A 执行后,唤醒 B,B 执行后唤醒 C,C 执行后再唤醒 A,这样循环的等待、唤醒来达到目的。
- public class OddEvenPrinter {
-
- private Object object = new Object();
- private final int limit;
- private volatile int count;
-
- OddEvenPrinter(int initCount, int times) {
- this.count = initCount;
- this.limit = times;
- }
-
- private void print() {
-
- synchronized (object) {
- while (count < limit){
- try {
- System.out.println(String.format("线程[%s]打印数字:%d", Thread.currentThread().getName(), ++count));
- object.notifyAll(); //通知宁外一个线程进入抢锁状态
- object.wait(); //释放锁,此线程进入等待队列
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- //防止有子线程被阻塞未被唤醒,导致主线程不退出
- object.notifyAll();
- }
- }
-
- public static void main(String[] args) {
- OddEvenPrinter printer = new OddEvenPrinter(0, 100);
- new Thread(printer::print, "奇数").start();
- new Thread(printer::print, "偶数").start();
- }
-
- }
-
第二题
思路:使用对象监视器实现,两个线程 A、B 竞争同一把锁,只要其中一个线程获取锁成功,就打印 ++i,并通知另一线程从等待集合中释放,然后自身线程加入等待集合并释放锁即可。
- package main.java.org.多线程Demo;
-
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
-
- /**
- * @param
- * @author XiaoSuDa
- * @description: $
- * @return $
- * @throws
- * @date $ $
- */
-
-
- public class PrinterABC {
- private int times; // 控制打印次数
- private int state; // 当前状态值:保证三个线程之间交替打印
- private Lock lock = new ReentrantLock();
-
- public PrinterABC(int times) {
- this.times = times;
- }
-
- public void print(String name,int currentState){
- for (int i = 0; i < times; ) {
- lock.lock();
- if (state % 3 == currentState){
- state++;
- i++;
- System.out.print(name);
- }
- lock.unlock();
- }
- }
-
- public static void main(String[] args) {
- //顺序打印10次
- PrinterABC printerABC = new PrinterABC(10);
-
- new Thread(() -> {
- printerABC.print("A", 0);
- }, "A").start();
-
- new Thread(() -> {
- printerABC.print("B", 1);
- }, "B").start();
-
- new Thread(() -> {
- printerABC.print("C", 2);
- }, "C").start();
- }
- }
-
第一题
思路:使用一个取模的判断逻辑 C%M ==N,题为 3 个线程,所以可以按取模结果编号:0、1、2,他们与 3 取模结果仍为本身,则执行打印逻辑。
- public class cu {
-
- public static void main(String[] args) throws InterruptedException {
- int n = 100;
- CountDownLatch count = new CountDownLatch(2);
- AddTest test1 = new AddTest(0, n / 2, count);
- AddTest test2 = new AddTest((n / 2) + 1, n, count);
- Thread t1 = new Thread(test1, "t1");
- Thread t2 = new Thread(test2, "t2");
- t1.start();
- t2.start();
- count.await();
- System.out.println("结果是:"+test1.getRes()+test2.getRes());
- }
- }
-
- class AddTest implements Runnable{
- private int begin;
- private int end;
- private int res;
- private CountDownLatch count;
-
- public AddTest(int begin, int end,CountDownLatch countDownLatch) {
- this.begin = begin;
- this.end = end;
- this.count = countDownLatch;
- }
- @Override
- public void run() {
- int sum = 0;
- for (int i = begin; i <= end; i++) {
- sum+=i;
- }
- res = sum;
- count.countDown(); //每次调用一个线程
- }
- public int getRes(){
- return res;
- }
- }
第六题
思路:创建两个线程,分别计算,利用countdownlunch,进行线程同步,然后返回