线程间的通信

1. 线程间通信概述

在程序运行过程中,线程是相对独立的单位,多个线程之间并行的执行,并不会有太多的沟通,每个线程都有属于自己的内存空间,且无法互相访问,所以可以认为多个线程之间是隔离的状态,并没有过多的信息传递。

而线程在并发运行的过程中,还会无序抢夺cpu,造成执行的顺序不确定,使执行的结果变得不可预期

有时我们希望能够实现 多个线程之间进行信息的传递 或 执行过程的协调 ,这样的技术称之为线程间的通信技术

线程间的通信技术:
共享内存机制 - 多个线程之间进行信息的传递
等待唤醒机制 - 多个线程执行过程的协调

2. 线程间的通信机制

共享内存机制 - 多个线程之间的信息传递
每个线程都各自有各自的内存空间,且无法互相访问,当多个线程需要进行信息的共享时,可以在多个线程都可以看到的公共的内存中保存数据,从而实现两者的通信

	案例:某一个线程通过控制一个布尔类型的信号量 控制另一个线程执行的流程
		package cn.tedu.thread;
		
		/**
		 * 线程间的通信 - 共享内存方式传递信息
		 */
		public class Demo03 {
			public static boolean canRun = true; 
			public static void main(String[] args) {
				new Thread(new Thread03_Master()).start();
				new Thread(new Thread03_Slave()).start();
			}
		}
		
		class Thread03_Master implements Runnable{
			@Override
			public void run() {
				try {
					Thread.sleep(2000);
					Demo03.canRun = false;
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		class Thread03_Slave implements Runnable{
			@Override
			public void run() {
				while(Demo03.canRun){
					System.out.println("小弟在运行。。。");
				}
				System.out.println("小弟告辞了。。。");
			}
		}

3. 线程之间的通信技术

等待唤醒机制 - 协调线程执行的先后顺序
多个线程在并发的过程中,互相抢夺cpu,造成执行的先后顺序是不确定的,如果需要控制线程的执行先后顺序,可以采用等待唤醒的机制

在锁对象身上,具有等待、唤醒的方法,这些方法其实是定义在Object类上的,所以任意对象作为锁对象时,都可以有等待 唤醒的方法使用

	 void	wait() 
		          在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
	 void	wait(long timeout) 
		          在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
	 void	wait(long timeout, int nanos) 
		          在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。
	 void	notify() 
		          唤醒在此对象监视器上等待的单个线程。
	 void	notifyAll() 
		          唤醒在此对象监视器上等待的所有线程。
	
	wait()
		在Synchronized代码块中,调用锁对象的wait方法将会使当前线程进入进入阻塞状态 不再争夺cpu 释放锁 阻塞的状态会一直持续下去 直到被其他线程 调用锁对象的notify()或notifyAll()方法唤醒
	
	notify()
		在Synchronized代码块中,调用锁对象的notify()方法,将会唤醒之前在这个锁对象上进入wait()状态的某一个线程,使其退出阻塞状态,退出阻塞状态后,恢复对cpu的争夺,但仍然需要得到锁,才可以继续运行。至于唤醒的是哪一个线程是不确定的
		
	notifyAll()
		在Synchronized代码块中,调用锁对象的notifyAll()方法,将会唤醒之前在这个锁对象上进入wait()状态的所有线程,使这些线程退出阻塞状态,退出阻塞状态后,恢复对cpu的争夺,但仍然需要得到锁,才可以继续运行。
	
	案例:修改之前的修改打印案例,实现修改和打印依次执行
	
		package cn.tedu.thread;
		
		/**
		 * 多线程并发安全问题
		 */
		public class Demo02 {
			public static String name = "马冬梅";
			public static String gender = "女";
			
			public static void main(String[] args) {
				new Thread(new PrintThread()).start();
				new Thread(new ChangeThread()).start();
			}
		}
		
		class ChangeThread implements Runnable{
			@Override
			public void run() {
				try {
					while(true){
						synchronized (Demo02.class) {
							if ("马冬梅".equals(Demo02.name)) {
								Demo02.name = "夏洛";
								Demo02.gender = "男";
							} else {
								Demo02.name = "马冬梅";
								Demo02.gender = "女";
							}
							//唤醒
							Demo02.class.notify();
							//等待
							Demo02.class.wait();
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		
		class PrintThread implements Runnable{
			@Override
			public void run() {
				try {
					while(true){
						synchronized (Demo02.class) {
							System.out.println("姓名:" + Demo02.name + ",性别:" + Demo02.gender);
							Demo02.class.notify();
							Demo02.class.wait();
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		
	案例:利用等待唤醒机制 实现一个阻塞式队列
		package cn.tedu.thread;
		
		import java.util.LinkedList;
		
		/**
		 * 等待唤醒机制 案例 - 实现阻塞式队列
		 * @author Administrator
		 *
		 */
		class MyBlockingQueue{
			private LinkedList queue = new LinkedList<>();
			private int MaxSize = 0;
			public MyBlockingQueue(int size) {
				this.MaxSize = size;
			}
			//--如果满了还要加 要阻塞当前操作线程
			public synchronized void add(Object obj){
				try {
					if(queue.size() >= this.MaxSize){
						//--不能往里加,阻塞当前线程,直到有人取走,队列变为非满
						this.wait();
					}
					queue.add(obj);
					this.notify();
				} catch (InterruptedException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				}
			}
			
			//--如果空了还要取 要阻塞当前操作线程
			public synchronized Object take(){
				try {
					if(queue.size() <=0 ){
						this.wait();
					}
					Object obj = queue.poll();
					this.notify();
					return obj;
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				}
			}
		}
		
		public class Demo04 {
			public static void main(String[] args) {
				MyBlockingQueue bq = new MyBlockingQueue(3);
				new Thread(new Runnable() {
					@Override
					public void run() {
						bq.add("aaa");
						bq.add("bbb");
						bq.add("ccc");
						bq.add("ddd");
						bq.add("eee");
					}
				}).start();
				
				new Thread(new Runnable() {
					@Override
					public void run() {
						System.out.println(bq.take());
						System.out.println(bq.take());
						System.out.println(bq.take());
						System.out.println(bq.take());
						System.out.println(bq.take());
					}
				}).start();
			}
		}

4线程间状态的转换

线程间的通信_第1张图片

你可能感兴趣的:(JAVASE)