`
不平凡的人
  • 浏览: 35227 次
  • 性别: Icon_minigender_1
  • 来自: 嘉峪关
社区版块
存档分类
最新评论

关于线程通信问题(面试题)

 
阅读更多

关于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使得线程休眠一段时间,会持有线程的锁;

 

 

  • 大小: 27.1 KB
  • 大小: 40.1 KB
  • 大小: 36.3 KB
  • 大小: 44.1 KB
分享到:
评论

相关推荐

    多线程面试题

    以上是对“多线程面试题”这一主题的简要概述,实际面试中可能会涉及到更深层次的问题,如并发模型、线程池的优化策略、线程安全的实现原理等。深入理解和熟练运用这些知识点,将有助于你在面试中脱颖而出,解决实际...

    java经典多线程面试题

    在Java中,多线程是一种非常重要的编程概念,...这些面试题涵盖了Java多线程编程的基础知识、同步机制、线程间通信以及并发集合类等多个方面。在准备面试时,对这些问题进行深入理解和准备,能够有效提升面试的成功率。

    线程面试题

    ### Java线程面试题知识点详解 #### 一、线程基本概念 1. **什么是线程?** - 线程是操作系统中能够独立运行的最小单位,它被包含在一个进程中,是进程中的实际执行单元。通过多线程编程可以有效利用多核处理器...

    浪潮面试题九月中旬去浪潮通信面试试题

    根据给定的浪潮通信面试题目,我们可以总结出以下几个重要的知识点: ### 1. Java 数组初始化及元素操作 **题目:** `String a[] = new String[10];` 选项: A: `a[0]`; B: `a[9] = null`; C: `a.length = 11;` **...

    java多线程面试题和答案

    以下是一些关于Java多线程的面试题及其答案,涵盖了基础概念、并发控制、线程安全以及性能优化等方面。 1. **什么是Java多线程?** 多线程是指在单个程序中同时执行多个线程,这样可以提高应用程序的效率和响应...

    73道Java面试题合集-多线程与进程

    以下是对73道Java面试题合集——多线程与进程相关知识点的详细解释。 1. **进程与线程的概念**: - **进程**:是操作系统资源分配的基本单位,拥有独立的内存空间和系统资源,可以并发执行。 - **线程**:是程序...

    多线程经典面试题和答案

    ### 多线程经典面试题解析 #### Java 实现线程的方式 1. **继承 `Thread` 类**:这是最直接的方式,通过继承 `Thread` 类,并重写 `run()` 方法来实现线程的逻辑。这种方式简单直接,但是因为 Java 不支持多重继承...

    线程同步面试题深入解析

    - 等待/唤醒机制:`wait()`、`notify()`和`notifyAll()`用于线程间的通信,控制线程的执行顺序。 - 锁的概念:每个对象有一个内置锁,线程执行同步代码时会获取这个锁,执行完成后释放。 4. **同步和非共享数据**...

    多线程,多线程面试题,C#源码.zip

    在IT领域,多线程是程序设计中的一个重要概念,尤其在C#这样...在面试中,面试官可能还会询问具体的性能优化策略、并发模型的理解、以及如何解决特定的多线程问题。通过深入学习和实践,开发者可以更好地应对这些挑战。

    网络面试题面试题汇总

    7. **面试与面试题**:面试技巧和常见面试问题的准备是求职者必须关注的,如自我介绍、项目经验分享、问题解决能力的展示等。 8. **下载与入门**:对于初学者,理解并获取相关学习资料、实践项目,以及如何快速入门...

    Java面试题大全(整理版)1000+面试题 (面试准备+Java基础+高级特性+常见问题+答案解析)

    这份全面的面试题资源包含了Java的各个方面,包括但不限于基础语法、面向对象、集合框架、多线程、异常处理、IO流、网络编程、反射、设计模式、JVM优化等。面试准备时,这些知识点都是不可或缺的。 对于MyBatis的...

    java常见面试题---线程篇

    以下是一些关于Java线程的常见面试知识点,这些内容可能出现在线程.doc文档中: 1. **线程的创建方式**: - 实现`Runnable`接口:创建一个类实现`Runnable`接口,并重写`run()`方法,然后将实例传递给`Thread`类的...

    c++笔试面试之网络和多线程

    本篇文档详细列举了关于网络部分的面试题目,同时也涉及了与多线程相关的TCP/IP协议栈的建立和断开过程。以下为详细的知识点总结: 1. TCP服务创建流程:在C++网络编程中,TCP服务的创建涉及以下几个步骤: - 创建...

    2021年JAVA开发面试题.zip

    3. **并发编程**:涉及线程同步与通信(synchronized、wait/notify、Lock接口)、并发工具类(如ExecutorService、Semaphore、CountDownLatch、CyclicBarrier)、并发容器(ConcurrentHashMap、CopyOnWriteArrayList...

    多线程面试题及回答

    以上总结了15个Java多线程面试题及其解答思路,涵盖了Java多线程的基本概念、实现技巧及常见问题。通过对这些问题的深入理解与实践,可以帮助求职者在面试中展现出扎实的Java多线程与并发技术功底。

    计算机和JAVA 面试题大全

    - 面试题:如何实现线程间的同步和通信? 10. **反射与注解** - 解释反射机制及其在运行时动态操作类和对象的能力。 - 面试题:如何通过反射创建并调用一个类的方法? - 讨论注解的用途,如代码自动生成、元...

    java面试题_多线程(68题)

    这里,我们将深入探讨与Java多线程相关的68个面试问题,涵盖基础知识、线程安全、同步机制、线程池、死锁等关键知识点。 1. **线程的生命周期**:Java中的线程有新建、就绪、运行、阻塞和死亡五种状态。理解这些...

    Java面试题和练习题

    本文将基于标题“Java面试题和练习题”以及描述中提到的内容,深入探讨Java相关的面试题和练习题,旨在帮助求职者或希望提升技能的开发者巩固知识,准备面试。 一、Java基础 1. Java的数据类型:了解Java的八种...

    面试题面试题面试题34

    面试题是评估求职者技能和知识的重要方式,特别是在IT领域。以下是对提供的面试题的详细解答: 1. **字符串翻转方法**: 实现字符串翻转,可以使用双指针技术,一个从字符串开头开始,另一个从末尾开始,交换它们...

    多线程,高并发面试题.pdf

    在Java多线程编程中,有一些问题和知识点是面试时经常会被问到的,比如关于线程停止的方法、线程同步与异步执行的差异、以及Java中两种不同线程同步机制(synchronized关键字和java.util.concurrent.locks.Lock接口...

Global site tag (gtag.js) - Google Analytics