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

简介: 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 是如何实现线程间通信的?


相关文章
|
6天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
2天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
15 9
|
1天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
9 2
|
5天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
2天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
5天前
|
Java
JAVA多线程通信:为何wait()与notify()如此重要?
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是实现线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件满足时被唤醒,从而确保数据一致性和同步。相比其他通信方式,如忙等待,这些方法更高效灵活。 示例代码展示了如何在生产者-消费者模型中使用这些方法实现线程间的协调和同步。
15 3
|
4天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
5天前
|
Java
java小知识—进程和线程
进程 进程是程序的一次执行过程,是系统运行的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程 线程,与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比
14 1
|
5天前
|
Java UED
Java中的多线程编程基础与实践
【10月更文挑战第35天】在Java的世界中,多线程是提升应用性能和响应性的利器。本文将深入浅出地介绍如何在Java中创建和管理线程,以及如何利用同步机制确保数据一致性。我们将从简单的“Hello, World!”线程示例出发,逐步探索线程池的高效使用,并讨论常见的多线程问题。无论你是Java新手还是希望深化理解,这篇文章都将为你打开多线程的大门。
|
1月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
40 1
C++ 多线程之初识多线程