关于volitale,notify,wait面试问题:
1、问题:两个线程操作一个对象时,使得其中的一个线程不要一直死循环等待另外一个线程
解决思路:上述情况如果不添加volatile关键字就会是一个线程一直循环等待
(1)代码示例:
package net.oschina.tkj.mulitcoding.notifykey; import java.util.ArrayList; import java.util.List; /** * notify,wait wait:使得线程处于等待状态,并且释放线程的锁 notify:唤醒一个线程,但是不释放锁,因此可能会产生线程信息不同步的问题 * notify与wait都是改变线程状态的方法,因此要放到synchronizd中 * * 1.如下问题:两个线程操作一个对象时,使得其中的一个线程不要一直死循环等待另外一个线程 * * 上述情况如果不添加volatile关键字就会是一个线程一直循环等待 * * * @author Freedom * */ public class NotifyWaitV1 { private static volatile List<String> list = new ArrayList<>(); public void add() { list.add("freedom"); } public int size() { return list.size(); } // 开启两个线程 public static void main(String[] args) { final NotifyWaitV1 v1 = new NotifyWaitV1(); Thread t1 = new Thread(new Runnable() { @Override public void run() { try { for (int i = 0; i < 10; i++) { v1.add(); System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素!"); Thread.sleep(100); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }, "t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { while (true) { if (v1.size() == 5) { System.out.println("当前线程:" + Thread.currentThread().getName() + " list.size==5退出循环,任务执行完成!"); throw new RuntimeException(); } } } }, "t2"); t2.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } t1.start(); } }
(2)结果展示:
①不添加“volatile”关键字
②添加volatile关键字
2、用volatile解决了,一个线程空等待的问题 但是,while循环浪费性能,有没有一种机制来解决该问题?
解决思路: 此时,可以使用notify,wait机制 通过执行结果可以得出,notify唤醒一个线程,但是不释放锁,示例中只有当t1线程执行结束之后,才会执行t2线程内容。
(1)代码示例
package net.oschina.tkj.mulitcoding.notifykey; import java.util.ArrayList; import java.util.List; /** * notify,wait wait:使得线程处于等待状态,并且释放线程的锁 notify:唤醒一个线程,但是不释放锁,因此可能会产生线程信息不同步的问题 * notify与wait都是改变线程状态的方法,因此要放到synchronizd中 * * 1.如下问题:两个线程操作一个对象时,使得其中的一个线程不要一直死循环等待另外一个线程 * * 上述情况如果不添加volatile关键字就会是一个线程一直循环等待 * * 问题2,用volatile解决了,一个线程空等待的问题 但是,while循环浪费性能,有没有一种机制来解决该问题? * * 此时,可以使用notify,wait机制 通过执行结果可以得出,notify唤醒一个线程,但是不释放锁, * 示例中只有当t1线程执行结束之后,才会执行t2线程内容 * * @author Freedom * */ public class NotifyWaitV2 { private static volatile List<String> list = new ArrayList<>(); private static final Object lock = new Object(); public void add() { list.add("freedom"); } public int size() { return list.size(); } // 开启两个线程 public static void main(String[] args) { final NotifyWaitV2 v1 = new NotifyWaitV2(); Thread t1 = new Thread(new Runnable() { @Override public void run() { try { synchronized (lock) { for (int i = 0; i < 10; i++) { v1.add(); System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素!"); Thread.sleep(100); if (v1.size() == 5) { System.out.println("当前线程:" + Thread.currentThread().getName() + " 发出了notify通知!"); lock.notify(); } } } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }, "t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { synchronized (lock) { if (v1.size() != 5) { try { lock.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("当前线程:" + Thread.currentThread().getName() + " list.size==5退出循环,任务执行完成!"); throw new RuntimeException(); } } }, "t2"); t2.start(); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } t1.start(); } }
(2)运行结果:
3、问题2通过notify,wait机制解决了循环空等对资源浪费的情况,但是如果对于高并发情况下大量数据,当执行到某个业务逻辑节点时,需要唤醒另外一个线程对当前节点数据处理,使用notify通知,并不解决线程间的实时通信问题(notify不释放线程的锁),所以需要考虑另外一种思路。
解决方案使用:CountDownLatch类对象
(1)代码示例
package net.oschina.tkj.mulitcoding.notifykey; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; /** * notify,wait wait:使得线程处于等待状态,并且释放线程的锁 notify:唤醒一个线程,但是不释放锁,因此可能会产生线程信息不同步的问题 * notify与wait都是改变线程状态的方法,因此要放到synchronizd中 * * ###问题1### 如下问题:两个线程操作一个对象时,使得其中的一个线程不要一直死循环等待另外一个线程 * * 上述情况如果不添加volatile关键字就会是一个线程一直循环等待 * * ###问题2### 用volatile解决了,一个线程空等待的问题 但是,while循环浪费性能,有没有一种机制来解决该问题? * 此时,可以使用notify,wait机制 通过执行结果可以得出,notify唤醒一个线程,但是不释放锁, * 示例中只有当t1线程执行结束之后,才会执行t2线程内容 * * ###问题3### notify与wait方法可以解决循环空转浪费资源的问题,但是没法解决,线程间消息的实时更新问题 因此,需要使用 * * @author Freedom * */ public class NotifyWaitV3 { private static volatile List<String> list = new ArrayList<>(); // private static final Object lock = new Object(); private static final CountDownLatch countDownLatch = new CountDownLatch(1); public void add() { list.add("freedom"); } public int size() { return list.size(); } // 开启两个线程 public static void main(String[] args) { final NotifyWaitV3 v1 = new NotifyWaitV3(); Thread t1 = new Thread(new Runnable() { @Override public void run() { try { // synchronized (lock) { for (int i = 0; i < 10; i++) { v1.add(); System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素!"); Thread.sleep(100); if (v1.size() == 5) { System.out.println("当前线程:" + Thread.currentThread().getName() + " 发出了countDown通知!"); // lock.notify(); countDownLatch.countDown(); } } // } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }, "t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { // synchronized (lock) { if (v1.size() != 5) { try { // lock.wait(); countDownLatch.await();// t2线程等待 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("当前线程:" + Thread.currentThread().getName() + " list.size==5退出循环,任务执行完成!"); throw new RuntimeException(); } // } }, "t2"); t2.start(); try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } t1.start(); } }
(2)运行结果:
4、总结
(1)volatile,可以解决多个线程共享数据时的可见性,但是没法保证原子性操作;
(2)wait使得线程处于等待状态,会释放线程的锁;
(3)notify唤醒一个线程,但是会持有线程的锁;
(4)sleep使得线程休眠一段时间,会持有线程的锁;
相关推荐
以上是对“多线程面试题”这一主题的简要概述,实际面试中可能会涉及到更深层次的问题,如并发模型、线程池的优化策略、线程安全的实现原理等。深入理解和熟练运用这些知识点,将有助于你在面试中脱颖而出,解决实际...
在Java中,多线程是一种非常重要的编程概念,...这些面试题涵盖了Java多线程编程的基础知识、同步机制、线程间通信以及并发集合类等多个方面。在准备面试时,对这些问题进行深入理解和准备,能够有效提升面试的成功率。
### Java线程面试题知识点详解 #### 一、线程基本概念 1. **什么是线程?** - 线程是操作系统中能够独立运行的最小单位,它被包含在一个进程中,是进程中的实际执行单元。通过多线程编程可以有效利用多核处理器...
根据给定的浪潮通信面试题目,我们可以总结出以下几个重要的知识点: ### 1. Java 数组初始化及元素操作 **题目:** `String a[] = new String[10];` 选项: A: `a[0]`; B: `a[9] = null`; C: `a.length = 11;` **...
以下是一些关于Java多线程的面试题及其答案,涵盖了基础概念、并发控制、线程安全以及性能优化等方面。 1. **什么是Java多线程?** 多线程是指在单个程序中同时执行多个线程,这样可以提高应用程序的效率和响应...
以下是对73道Java面试题合集——多线程与进程相关知识点的详细解释。 1. **进程与线程的概念**: - **进程**:是操作系统资源分配的基本单位,拥有独立的内存空间和系统资源,可以并发执行。 - **线程**:是程序...
### 多线程经典面试题解析 #### Java 实现线程的方式 1. **继承 `Thread` 类**:这是最直接的方式,通过继承 `Thread` 类,并重写 `run()` 方法来实现线程的逻辑。这种方式简单直接,但是因为 Java 不支持多重继承...
- 等待/唤醒机制:`wait()`、`notify()`和`notifyAll()`用于线程间的通信,控制线程的执行顺序。 - 锁的概念:每个对象有一个内置锁,线程执行同步代码时会获取这个锁,执行完成后释放。 4. **同步和非共享数据**...
在IT领域,多线程是程序设计中的一个重要概念,尤其在C#这样...在面试中,面试官可能还会询问具体的性能优化策略、并发模型的理解、以及如何解决特定的多线程问题。通过深入学习和实践,开发者可以更好地应对这些挑战。
7. **面试与面试题**:面试技巧和常见面试问题的准备是求职者必须关注的,如自我介绍、项目经验分享、问题解决能力的展示等。 8. **下载与入门**:对于初学者,理解并获取相关学习资料、实践项目,以及如何快速入门...
这份全面的面试题资源包含了Java的各个方面,包括但不限于基础语法、面向对象、集合框架、多线程、异常处理、IO流、网络编程、反射、设计模式、JVM优化等。面试准备时,这些知识点都是不可或缺的。 对于MyBatis的...
以下是一些关于Java线程的常见面试知识点,这些内容可能出现在线程.doc文档中: 1. **线程的创建方式**: - 实现`Runnable`接口:创建一个类实现`Runnable`接口,并重写`run()`方法,然后将实例传递给`Thread`类的...
本篇文档详细列举了关于网络部分的面试题目,同时也涉及了与多线程相关的TCP/IP协议栈的建立和断开过程。以下为详细的知识点总结: 1. TCP服务创建流程:在C++网络编程中,TCP服务的创建涉及以下几个步骤: - 创建...
3. **并发编程**:涉及线程同步与通信(synchronized、wait/notify、Lock接口)、并发工具类(如ExecutorService、Semaphore、CountDownLatch、CyclicBarrier)、并发容器(ConcurrentHashMap、CopyOnWriteArrayList...
以上总结了15个Java多线程面试题及其解答思路,涵盖了Java多线程的基本概念、实现技巧及常见问题。通过对这些问题的深入理解与实践,可以帮助求职者在面试中展现出扎实的Java多线程与并发技术功底。
- 面试题:如何实现线程间的同步和通信? 10. **反射与注解** - 解释反射机制及其在运行时动态操作类和对象的能力。 - 面试题:如何通过反射创建并调用一个类的方法? - 讨论注解的用途,如代码自动生成、元...
这里,我们将深入探讨与Java多线程相关的68个面试问题,涵盖基础知识、线程安全、同步机制、线程池、死锁等关键知识点。 1. **线程的生命周期**:Java中的线程有新建、就绪、运行、阻塞和死亡五种状态。理解这些...
本文将基于标题“Java面试题和练习题”以及描述中提到的内容,深入探讨Java相关的面试题和练习题,旨在帮助求职者或希望提升技能的开发者巩固知识,准备面试。 一、Java基础 1. Java的数据类型:了解Java的八种...
面试题是评估求职者技能和知识的重要方式,特别是在IT领域。以下是对提供的面试题的详细解答: 1. **字符串翻转方法**: 实现字符串翻转,可以使用双指针技术,一个从字符串开头开始,另一个从末尾开始,交换它们...
在Java多线程编程中,有一些问题和知识点是面试时经常会被问到的,比如关于线程停止的方法、线程同步与异步执行的差异、以及Java中两种不同线程同步机制(synchronized关键字和java.util.concurrent.locks.Lock接口...