• 【多线程】多线程实际操作测试题


    经典面试题
    下面是多线程顺序打印的经典面试题

    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的和,然后返回和

    思路:要么控制线程顺序,要么利用条件竞争锁


    Semaphore

    1. public static void main(String[] args) {
    2. Semaphore s1 = new Semaphore(1);
    3. Semaphore s2 = new Semaphore(0);
    4. Semaphore s3 = new Semaphore(0);
    5. Thread t1 = new Thread(() -> {
    6. for (int i = 0; i < 10; i++) {
    7. try {
    8. s1.acquire();
    9. System.out.println("A");
    10. s2.release();
    11. } catch (InterruptedException e) {
    12. e.printStackTrace();
    13. }
    14. }
    15. });
    16. Thread t2 = new Thread(() -> {
    17. for (int i = 0; i < 10; i++) {
    18. try {
    19. s2.acquire();
    20. System.out.println("B");
    21. s3.release();
    22. } catch (InterruptedException e) {
    23. e.printStackTrace();
    24. }
    25. }
    26. });
    27. Thread t3 = new Thread(() -> {
    28. for (int i = 0; i < 10; i++) {
    29. try {
    30. s3.acquire();
    31. System.out.println("C");
    32. s1.release();
    33. } catch (InterruptedException e) {
    34. e.printStackTrace();
    35. }
    36. }
    37. });
    38. t1.start();
    39. t2.start();
    40. t3.start();
    41. }

    第一题

    1. public static void test(int nums){
    2. Semaphore s1 = new Semaphore(1);
    3. Semaphore s2 = new Semaphore(0);
    4. AtomicInteger x = new AtomicInteger(0);
    5. Thread t1 = new Thread(() -> {
    6. try {
    7. for (int i = 0; i < nums/2; i++) {
    8. s1.acquire();
    9. System.out.println("线程1 " + x);
    10. x.getAndIncrement();
    11. s2.release();
    12. }
    13. } catch (InterruptedException e) {
    14. e.printStackTrace();
    15. }
    16. });
    17. Thread t2 = new Thread(() -> {
    18. try {
    19. for (int i = 0; i < nums/2; i++) {
    20. s2.acquire();
    21. System.out.println("线程2 " + x);
    22. x.getAndIncrement();
    23. s1.release();
    24. }
    25. } catch (InterruptedException e) {
    26. e.printStackTrace();
    27. }
    28. });
    29. t1.start();
    30. t2.start();
    31. }

    第二题


    使用 wait/notify

    1. public class BBB {
    2. Object object = new Object();
    3. public int state;
    4. public int times;
    5. public BBB(int times) {
    6. this.times = times;
    7. }
    8. public void printABC(String name,int currentstate){
    9. for (int i = 0; i < times; i++)
    10. synchronized (object) {
    11. while (state % 3 != currentstate) {
    12. try {
    13. object.wait();
    14. } catch (InterruptedException e) {
    15. e.printStackTrace();
    16. }
    17. }
    18. state++;
    19. System.out.print(name);
    20. object.notifyAll();
    21. }
    22. }
    23. public static void main(String[] args) {
    24. BBB bbb = new BBB(10);
    25. new Thread(()->{
    26. bbb.printABC("A",0);
    27. }).start();
    28. new Thread(()->{
    29. bbb.printABC("B",1);
    30. }).start();
    31. new Thread(()->{
    32. bbb.printABC("C",2);
    33. }).start();
    34. }
    35. }

    第一题

    思路:还是以第一题为例,我们用对象监视器来实现,通过 wait 和 notify() 方法来实现等待、通知的逻辑,A 执行后,唤醒 B,B 执行后唤醒 C,C 执行后再唤醒 A,这样循环的等待、唤醒来达到目的

    1. public class OddEvenPrinter {
    2. private Object object = new Object();
    3. private final int limit;
    4. private volatile int count;
    5. OddEvenPrinter(int initCount, int times) {
    6. this.count = initCount;
    7. this.limit = times;
    8. }
    9. private void print() {
    10. synchronized (object) {
    11. while (count < limit){
    12. try {
    13. System.out.println(String.format("线程[%s]打印数字:%d", Thread.currentThread().getName(), ++count));
    14. object.notifyAll(); //通知宁外一个线程进入抢锁状态
    15. object.wait(); //释放锁,此线程进入等待队列
    16. } catch (InterruptedException e) {
    17. e.printStackTrace();
    18. }
    19. }
    20. //防止有子线程被阻塞未被唤醒,导致主线程不退出
    21. object.notifyAll();
    22. }
    23. }
    24. public static void main(String[] args) {
    25. OddEvenPrinter printer = new OddEvenPrinter(0, 100);
    26. new Thread(printer::print, "奇数").start();
    27. new Thread(printer::print, "偶数").start();
    28. }
    29. }

    第二题

    思路:使用对象监视器实现,两个线程 A、B 竞争同一把锁,只要其中一个线程获取锁成功,就打印 ++i,并通知另一线程从等待集合中释放,然后自身线程加入等待集合并释放锁即可


    使用Lock(ReentrantLock)

    1. package main.java.org.多线程Demo;
    2. import java.util.concurrent.locks.Lock;
    3. import java.util.concurrent.locks.ReentrantLock;
    4. /**
    5. * @param
    6. * @author XiaoSuDa
    7. * @description: $
    8. * @return $
    9. * @throws
    10. * @date $ $
    11. */
    12. public class PrinterABC {
    13. private int times; // 控制打印次数
    14. private int state; // 当前状态值:保证三个线程之间交替打印
    15. private Lock lock = new ReentrantLock();
    16. public PrinterABC(int times) {
    17. this.times = times;
    18. }
    19. public void print(String name,int currentState){
    20. for (int i = 0; i < times; ) {
    21. lock.lock();
    22. if (state % 3 == currentState){
    23. state++;
    24. i++;
    25. System.out.print(name);
    26. }
    27. lock.unlock();
    28. }
    29. }
    30. public static void main(String[] args) {
    31. //顺序打印10次
    32. PrinterABC printerABC = new PrinterABC(10);
    33. new Thread(() -> {
    34. printerABC.print("A", 0);
    35. }, "A").start();
    36. new Thread(() -> {
    37. printerABC.print("B", 1);
    38. }, "B").start();
    39. new Thread(() -> {
    40. printerABC.print("C", 2);
    41. }, "C").start();
    42. }
    43. }

    第一题

    思路:使用一个取模的判断逻辑 C%M ==N,题为 3 个线程,所以可以按取模结果编号:0、1、2,他们与 3 取模结果仍为本身,则执行打印逻辑


    CountDownLatch

    1. public class cu {
    2. public static void main(String[] args) throws InterruptedException {
    3. int n = 100;
    4. CountDownLatch count = new CountDownLatch(2);
    5. AddTest test1 = new AddTest(0, n / 2, count);
    6. AddTest test2 = new AddTest((n / 2) + 1, n, count);
    7. Thread t1 = new Thread(test1, "t1");
    8. Thread t2 = new Thread(test2, "t2");
    9. t1.start();
    10. t2.start();
    11. count.await();
    12. System.out.println("结果是:"+test1.getRes()+test2.getRes());
    13. }
    14. }
    15. class AddTest implements Runnable{
    16. private int begin;
    17. private int end;
    18. private int res;
    19. private CountDownLatch count;
    20. public AddTest(int begin, int end,CountDownLatch countDownLatch) {
    21. this.begin = begin;
    22. this.end = end;
    23. this.count = countDownLatch;
    24. }
    25. @Override
    26. public void run() {
    27. int sum = 0;
    28. for (int i = begin; i <= end; i++) {
    29. sum+=i;
    30. }
    31. res = sum;
    32. count.countDown(); //每次调用一个线程
    33. }
    34. public int getRes(){
    35. return res;
    36. }
    37. }

    第六题

    思路:创建两个线程,分别计算,利用countdownlunch,进行线程同步,然后返回

  • 相关阅读:
    mac m1 docker安装nacos
    css经典面试题(二)
    【Linux网络】DHCP原理与配置
    SCS【10】单细胞转录组之差异表达分析 (Monocle 3)
    Mysql编译安装和yum安装
    再学责任链和代理模式
    常用Linux命令
    两个关键词带你了解容器技术的实现
    火狐挂代理访问问题Software is preventing Firefox from safely connecting to this site
    杭电oj 2046 骨牌铺方格 C语言
  • 原文地址:https://blog.csdn.net/m0_46628950/article/details/126724761