线程之间的通讯

硅谷探秘者 2920 0 0

1.什么是线程通信

        线程之间通信的两个基本问题是互斥和同步。

        线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。


2.syncrhoized加锁的线程的Object类的wait()/notify()/notifyAll()

       1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。

  2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁)

  3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;

  4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程;


        如果调用某个对象的wait()方法,当前线程必须拥有这个对象的monitor(即锁),因此调用wait()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。如果当前线程没有这个对象的锁就调用wait()方法,则会抛出IllegalMonitorStateException.

        调用某个对象的wait()方法,相当于让当前线程交出(释放)此对象的monitor,然后进入等待状态,等待后续再次获得此对象的锁(Thread类中的sleep方法使当前线程暂停执行一段时间,从而让其他线程有机会继续执行,但它并不释放对象锁);  

        notify()方法能够唤醒一个正在等待该对象的monitor的线程,当有多个线程都在等待该对象的monitor的话,则只能唤醒其中一个线程,具体唤醒哪个线程则不得而知。 同样地,调用某个对象的notify()方法,当前线程也必须拥有这个对象的monitor,因此调用notify()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。

nofityAll()方法能够唤醒所有正在等待该对象的monitor的线程,这一点与notify()方法是不同的。


3.案例:生产者消费者交替执行

商品:

package threadTest.test2;

public class Goods {
	private String name;
	private Integer price;
	private boolean hav=false;
	
	public synchronized void make(String name,Integer price) {
		if(hav) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.name=name;
		this.price=price;
		this.hav=true;
		System.out.println("生产者生产:"+this.getName()+"--"+this.price);
		notify();
	}
	
	public synchronized void xiaofei() {
		if(!hav) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("消费者消费:"+this.name+"--"+this.price);
		this.hav=false;
		notify();
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Goods() {
		super();
		// TODO Auto-generated constructor stub
	}

	public Integer getPrice() {
		return price;
	}

	public void setPrice(Integer price) {
		this.price = price;
	}

	public boolean isHav() {
		return hav;
	}

	public void setHav(boolean hav) {
		this.hav = hav;
	}
}
//生产者
package threadTest.test2;

public class ShengChanZhe implements Runnable{

	private Goods goods;
	
	public ShengChanZhe(Goods goods) {
		this.goods=goods;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<10;i++) {
			if(i%2==0) {
				goods.make("手机",1500);
			}else {
				goods.make("电脑",4560);
			}
		}
	}
}

消费者

package threadTest.test2;

public class XiaoFeiZhe implements Runnable{
	private Goods goods;
	
	public XiaoFeiZhe(Goods goods) {
		this.goods=goods;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<10;i++) {
			goods.xiaofei();
		}
	}
}

测试代码:

package threadTest.test2;


public class Test1 {
	public static void main(String[] args) {
		
		Goods g=new Goods();
		
		Thread t=new Thread(new ShengChanZhe(g));
		t.setName("生产者");
		t.start();
		
		Thread t2=new Thread(new XiaoFeiZhe(g));
		t2.setName("消费者");
		t2.start();
	}
}

image.png


猜你喜欢
java基础 1224 java线生产者消费者模式生产者消费者模式是并发、多线中经典设计模式,生产者和消费者过分离执行工作解耦,简化了开发模式,生产者和消费者可以以不同速度生产和消费数据。一个生产和消
java基础 1535 1.先看一下线生命周期转换图(学java此图必背)本篇文章主要目不是分析线各种状态转换,而主要是研究一下线机制,以及Objectwait方法和notify方法。所以
java基础 7194 线带来问题:线有时候回和其他线共享一些资源,比如内存、数据库等。当多个线同时读写同一份共享资源时候,可能会发生冲突。这时候,我们就需要引入线“同步”机制,即各位线要有顺序使用
weblog 958 根本区别:进是操作系统资源分配基本单位,而线是处理器任务调度和执行基本单位。包含关系:一个进内可以有多个线(默认有一个主线),线是进一部分,必须依赖于进而存在,不能独立存在。资源共享:进是不共享资源,多个线是共享资源,所以存在资源竞争问题。
official 735 《操作系统》什么是进信顾名思义,进信就是指进信息交换。进是分配系统资源单位(包括内存地址空),因此各进拥有内存地址空相互独立。为了保证安全,一个进不能直接访问另一个进
java基础 1564 Java分为两种线:用户线和守护线所谓守护线是指在序运行时候在后台提供一种用服务线,比如垃圾回收线就是一个很称职守护者,并且这种线并不属于序中不可或缺部分。因此,当所有
java基础 2491 ”。线对象被创建后,其它线调用了该对象start()方法,从而来启动该线。例如,thread.start()。处于就绪状态线,随时可能被CPU调度执行。3.运行状态(Running):线获取C
official 724 《操作系统》什么是线,为什么要引入线?还没引入进前,系统中各个序只能串行执行。所以只能一个进执行完才能执行另外一个进。进入了进概念后,多个进可以并行执行,从而实现了用户在计
归档
2018年11月  12 2018年12月  33 2019年01月  28 2019年02月  28 2019年03月  32 2019年04月  27 2019年05月  33 2019年06月  6 2019年07月  12 2019年08月  12 2019年09月  21 2019年10月  8 2019年11月  15 2019年12月  25 2020年01月  9 2020年02月  5 2020年03月  16 2020年04月  4 2020年06月  1 2020年07月  7 2020年08月  13 2020年09月  9 2020年10月  5 2020年12月  3 2021年01月  1 2021年02月  5 2021年03月  7 2021年04月  4 2021年05月  4 2021年06月  1 2021年07月  7 2021年08月  2 2021年09月  8 2021年10月  9 2021年11月  16 2021年12月  14 2022年01月  7 2022年05月  1 2022年08月  3 2022年09月  2 2022年10月  2 2022年12月  5 2023年01月  3 2023年02月  1 2023年03月  4 2023年04月  2 2023年06月  3 2023年07月  4 2023年08月  1 2023年10月  1 2024年02月  1
标签
算法基础 linux 前端 c++ 数据结构 框架 数据库 计算机基础 储备知识 java基础 ASM 其他 深入理解java虚拟机 nginx git 消息中间件 搜索 maven redis docker dubbo vue 导入导出 软件使用 idea插件 协议 无聊的知识 jenkins springboot mqtt协议 keepalived minio mysql ensp 网络基础 xxl-job rabbitmq haproxy srs 音视频 webrtc javascript
目录
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。