线程之间通讯--wait和notify

GDB调试器及调试方法 GDB调试器及调试方法一、GDB简介二、gdb的使用1、启动gdb2、gdb命令3、gdb调试举例4、内存出错的gdb调试 一、GDB简介 • GDB : GNU Debugger,是GNU工程为GNU操作系统开发的 调试器,但它的使用不局限于GNU操作系统, GDB可以运行 在UNIX、Linux甚至Microsoft Windows。 • GDB可以调试C、C++、Objective-C、Pascal、Ada等语言编 写的程序;被调试的程序可以跟GDB运行于同一台电脑,也可 运行于不同电脑。 • 使用G 阅读详情

使用wait / notify方法实现线程间的通信。(注意这两个方法都是object的类的方法,换句话说java为所有的对象都提供了这两个方法)

1 wait 和 notify 必须配合synchronized 关键字使用

2wait方法释放锁,notify方法不释放锁。

package com.bjsxt.base.conn008;

import java.util.ArrayList;
import java.util.List;
/**
 * wait notfiy 方法,wait释放锁,notfiy不释放锁
 * @author alienware
 *
 */
public class ListAdd2 {
	private volatile static List<String> list = new ArrayList<String>();	
	
	public void add(){
		list.add("bjsxt");
	}
	public int size(){
		return list.size();
	}
	
	
	public static void main(String[] args) {
		final ListAdd2 list2 = new ListAdd2();
		
		// 1 实例化出来一个 lock
		// 当使用wait 和 notify 的时候 , 一定要配合着synchronized关键字去使用
		final Object lock = new Object();
		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					synchronized (lock) {
						for(int i = 0; i <10; i++){
							list2.add();
							System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");
							Thread.sleep(500);
							if(list2.size() == 5){
								System.out.println("已经发出通知..");
								lock.notify();
							}
						}						
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

			}
		}, "t1");
		
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				synchronized (lock) {
					if(list2.size() != 5){
						try {
							lock.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止..");
					throw new RuntimeException();
				}
			}
		}, "t2");	
		
		t2.start();
		/**
		 * t1与t2的联系是他们使用了同一个类锁,就是Object
		 * 
		 * t2先开始执行,得到lock锁,于是t1排队等待lock的释放,
		 * t2执行到lock.wait();t2将进行wait等待,将锁给释放, t1得到锁,开始执行
		 * t1执行到list.size()==5,将t2给唤醒(lock.nofity),但是调用notify,不会释放t1的锁,所以t1继续循环
		 * t1循环10次结束后,锁得到了释放,于是t2继续执行
		 */
		t1.start();
	}
}
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
已经发出通知..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t2收到通知线程停止..
Exception in thread "t2" java.lang.RuntimeException
	at com.naixue.vip.p6.netty.handler.ListAdd2$2.run(ListAdd2.java:62)
	at java.base/java.lang.Thread.run(Thread.java:834)

 

使用wait,nofify模拟Queue:

 

BlockingQueue: 顾名思义,首先它是一个队列,并且支持阻塞的机制,阻塞的放入和得到数据。我们要实现LinkedBlockingQueue下面两个简单的方法put和take。

put(anObject):把anObject加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断,直到BlockingQueue里面有空间再继续.

take:取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到BlockingQueue有新的数据被加入.

package com.bjsxt.base.conn009;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class MyQueue {
	
	//1 需要一个承装元素的集合 
	private LinkedList<Object> list = new LinkedList<Object>();
	
	//2 需要一个计数器
	private AtomicInteger count = new AtomicInteger(0);
	
	//3 需要制定上限和下限
	private final int minSize = 0;
	
	private final int maxSize ;
	
	//4 构造方法
	public MyQueue(int size){
		this.maxSize = size;
	}
	
	//5 初始化一个对象 用于加锁
	private final Object lock = new Object();
	
	
	//put(anObject): 把anObject加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断,直到BlockingQueue里面有空间再继续.
	public void put(Object obj){
		synchronized (lock) {
			while(count.get() == this.maxSize){
				try {
					lock.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			//1 加入元素
			list.add(obj);
			//2 计数器累加
			count.incrementAndGet();
			//3 通知另外一个线程(唤醒)
			lock.notify();
			System.out.println("新加入的元素为:" + obj);
		}
	}
	
	
	//take: 取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到BlockingQueue有新的数据被加入.
	public Object take(){
		Object ret = null;
		synchronized (lock) {
			while(count.get() == this.minSize){
				try {
					lock.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			//1 做移除元素操作
			ret = list.removeFirst();
			//2 计数器递减
			count.decrementAndGet();
			//3 唤醒另外一个线程
			lock.notify();
		}
		return ret;
	}
	
	public int getSize(){
		return this.count.get();
	}
	
	
	public static void main(String[] args) {
		
		final MyQueue mq = new MyQueue(5);
		mq.put("a");
		mq.put("b");
		mq.put("c");
		mq.put("d");
		mq.put("e");
		
		System.out.println("当前容器的长度:" + mq.getSize());
		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				mq.put("f");
				mq.put("g");
			}
		},"t1");
		
		t1.start();
		
		
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				Object o1 = mq.take();
				System.out.println("移除的元素为:" + o1);
				Object o2 = mq.take();
				System.out.println("移除的元素为:" + o2);
			}
		},"t2");
		
		
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		t2.start();
	}
}

 

 

 

我们的程序为什么需要头文件 什么是源文件、什么是头文件 我所见到的最好的答案: 通常,在一个 C++ 程序中,只包含两类文件―― .cpp 文件和 .h 文件。其中,.cpp 文件被称作 C++ 源文件,里面放的都是 C++ 的源代码;而 .h 文件则被称作 C++ 头文件,里面放的也是 C++ 的源代码。 个人理解: 我们为一个工程或项目所写的所有程序文件都可以被称为源文件。其中源文件包括头文件(C语言的.h文件 \ C+... 阅读详情

相关推荐

程序在Debug模式下运行正常而在Release模式下运行出错的解决方案

背景 以前在网上查资料的时候,无意中开发别人出现过这样的一个问题:“程序在Debug模式下运行正常,而在Release模式下运行出错”。当时就下意识认为,这不可能,肯定是代码有改动了!但,当自己写的一个小程序出现了这个问题后,才开始正式这个问题。 现在把当时解决问题的一些思路总结下,分享给大家,希望大家少走弯路吧。 分析过程 在VS开发环境中,Debug模式和Release模式并没有本质上的区别,...

it草稿纸 1万+

多线程-----单线程之间的通信wait和notify

一、场景 有若干订单存放到list集合或者队列中,我们不知道什么是满了或者没有订单, 第一种方式:一般会隔固定时间去看list中是否有时间,有了则进行处理,没有则退出,这样一直循环。 第二种方式:就是利用线程之间的通信机制,也就是wait和notify,如果list存放的订单达到了最大限制或者list为空(大小为0),则wait,阻塞线程,否则notify,唤醒线程。 二、wait和not...

燕少江湖 776

exe程序运行出错退出,使用windbg查找出错位置

现象说明:2011年6月22日,自己编译的exe程序在用户虚拟机上运行起来就出错退出,此现象只在此一台机器上出现,其他机器和开发机器均不出现此问题,此程序代码量很大,此种情况一时无法解决。最终解决方案:在同事的帮助下,使用windbg工具,远程调试客户机器,找到原因所在及问题出错位置和函数,出错位置为获取用户硬盘序列号的时候,buf[20]全部为空格,在左右空格并两两颠倒的时候操作内存

good_gdz的专栏 1145

线程间的通信---wait()、notify()

wait() 作用:让当前线程进入等待状态(使线程停止运行),同时,wait()也会让当前线程释放它所持有的锁,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,当前线程被唤醒(进入“就绪态”) 注意: 1.方法wait()的作用是使当前执行代码的线程进行等待,wait()方法是Object类的方法,该方法是用来将当前线程置入“预执行队列”中,并且在wait()所在的代码处停止执行,直到接到通知或被中断为止。 2. wait()方法只能在同步方法中或同步块中调用。如果..

m0_46657493的博客 1277

VOTtoolkit的使用【3.调试方法】

用过VOTtoolkit的都知道,它是没有办法在运行时进行断点调试的,运行出错会直接退出,并且不会提示任何与程序相关的出错信息,因此今天在这里分享一下我平时调试用的方法。 实际上VOTtoolkit在运行时会生成log信息,并保存在vot-workspace/logs/tracer-name/目录下,log的名字通常是时间信息,例如20190322T085119.log和20190322T085...

TS____4的博客 2314

小程序开发调试指南

一些线上问题需要在真机中进行调试或日志输出,为方便查看前端日志的输出,App 端提供了调试模式, 打开调试模式后面板界面中会显示 vConsole 按钮,点击后可打开手机端 vConsole界面查看日志输出。

IoT砖家 3487

Java线程基础(13):wait()和notify()

简介 本文讲解Java中wait()、notify(),通过一个标准的使用实例,来讨论下这两个方法的作用和使用时注意点,这两个方法被提取到顶级父类Object对象中,地位等同于toString()方法。 一、wait()和notify()含义 wait()方法是让当前线程等待的,即让线程释放了对共享对象的锁,不再继续向下执行。 wait(long timeout)方法可以指定一个超时时间,过了这个时间如果没有被notify()唤醒,则函数还是会返回。如果传递一个负数timeout会抛出I...

mingyuli的博客 1万+

如何根据异常提示信息找出程序出错代码(VC6)

<br />看到网上说在debug下可以找到预料的崩溃地址行,但是实际上没有什么用呀。<br />(既然在debug下,那直接用调试器找不更好吗?费这么大劲干什么)(转的文章在后面)<br /><br />Release版本(指编译器优化后的),要找崩溃地址行就比较费劲了。<br />linux下的方法:<br />1、使之生成core dump文件<br />2、gdb调试该core文件<br />3、根据大概的堆栈信息,运行disassemble (具体用法见gdb帮助)<br />4、根据崩溃地址找到

luxiaoyu_sdc的专栏 8207

JAVA多线程基础篇-线程通信(wait/notify)

在JAVA多线程中,线程通信是重要概念之一。线程通信能够使系统之间的交互性更强大,在大大提高CPU利用率的同时还会使程序员对各线程在任务处理过程中进行有效把控。本文将针对使用wait/notify进行线程之间通信进行分析,详述其实现过程、原理以及相关注意事项。.........

qq_33479841的博客 2301

程序崩溃的调试方法及原因分类

作者 邵发 官网 http://afanihao.cn 本文是 C/C++学习指南(补充篇)- 单步调试 的官方文档。。。程序崩溃的原因分类 1. 函数栈溢出 一个变量未初化、未赋值,就读取它的值。 ( 这属于逻辑问题,往往是粗心大意的导致的 ) 2. 函数栈溢出 (1)定义了一个体积太大的局部变量 (2)函数嵌套调用,层次过深(如无穷递归) 3. 数组越界访问 访问数组元素时,下标越界 4. 指针

阿发你好 2万+

为release版程序保留符号表方便调试

一般来说,习惯上为debug版程序加入调试信息,release版程序不加调试信息。 这样做有一个缺点,如果程序中没有加入调试信息,在程序发生崩溃时,就不得不去分析程序的汇编代码,这会增加定位问题的难度。并不是所有人都能看得懂汇编。 反过来,如果在release版中加入调试信息,那么使用程序的人就很容易能看到我们的代码,这是我们不希望看到的。 其实,可以用strip程序

elated的专栏 3907

线程之间的通信—wait()、notify()、notifyAll()

wait()和notify()是进行线程间通讯的两个重要的方法。 1.wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”) 2.notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,...

qq_45036591的博客 1102

DirectX11 调试Direct3D应用程序

调试Direct3D应用程序 1. 如何调试Direct3D应用程序? 我们实现了一个宏,用它来检查许多Direct3D函数返回的HRESULT值。这个宏定义在d3dUtil.h文件中:#if defined(DEBUG) | defined(_DEBUG) #ifndef HR #define HR(x)

梦幻DUO的游戏开发之路 2125

Visual Studio环境下生成dump文件及利用dump文件定位程序出错位置

今天在网上学习了关于dump文件

wangzhen_cv的专栏 7875

如何使用Visual C++调试程序?

如何使用Visual C++调试程序?                      作者:贾迎乐            与 DOS 程序相比,Windows 程序动辄达几万行、十几万行,调试相当复杂。幸好 Visual C++ 提供了功能强大的调试器( Debugger ),使我们可以在源代码、汇编级别上进行调试,在调试中可以使用断言、TRACE 宏输出结合单步执行来综合调试。    1

4260

如果一个程序跑10000次只失败一次,你会怎么调试?

CLR小组中存在着大量的回归测试,这些回归测试会定期执行来发现CLR中的Bug,Developer在Checkin之前,也需要执行这些测试的一部分(大概是10小时左右,如果全部跑的话估计要好几天)。这些测试对于保证CLR的质量是至关重要的。有时候,这些测试会偶尔失败,比如跑100次失败大概一到两次,有些极端的例子甚至是10000次才失败一次。像这种问题通常是很难调试的。在前面调试Bug的神兵利器:

张羿的优快云专栏 3万+

VS的调试功能小结

巧用VS的调试功能可以帮助我们更好的理解程序,追踪变量各种值的变化等等,对循环、函数和递归的学习也有帮助。 如果你已经掌握了VS调试技巧,本文可以跳过(去年的稿qaq)。 以下内容主要摘自网络。 写在前面[1] 初学 C 语言程序设计,往往一看到自己编的程序出现错误就不知所措了。有些同学上机时,只要程序能够顺利运行,就认为大功告成,根本没想到程序还存在某些隐患。要想不犯或少犯错误,就需要了解 C 语言程序设计的错误类型和纠正方法。 C 语言程序设计的错误可分为语法错误、连接错误、逻辑错误和运行错

ACM2017 6319

Linux的gdb调试

Debug 版本为可调式版本,生成的可执行文件中包含调试需要的信息。我们作为开发人员,最常用的就是 debug 版本的可执行文件。Debug 版本的生成:因为调试信息是在编译过程时加入到中间文件(.o)中的,所以必须在编译时控制其生成包含调试信息的中间文件。所以debug版本的体积要大一些。gcc -c hello.c -g —> 生成包含调试信息的中间文件或者。

ljy的博客 1225
上一篇: ThreadLocal
下一篇: 操作系统一些玩法/去空行
wive
博客等级 码龄14年 33粉丝 119原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值