Java基础笔记:Day_15 线程通信

一、线程通信

1.生产者与消费者案例
在这里插入图片描述
分析案例:
①生产者和消费者应该操作共享的资源(实现方式)
②使用一个或多个线程来表示生产者
③使用一个或多个线程来表示消费者

代码实例:

//生产者类
public class Producer implements Runnable {
	private ProducerAndConsumer resource = null;

	public Producer(ProducerAndConsumer resource) {
		this.resource = resource;
	}

	public void run() {
		for (int i = 0; i < 50; i++) {
			if (i % 2 == 0) {
				resource.push("Mille", "Male");
			} else {
				resource.push("Felece", "Female");
			}
		}
	}
}
--------------------------------------------------------
//消费者类
public class Consumer implements Runnable {
	private ProducerAndConsumer resource = null;
	
	public Consumer(ProducerAndConsumer resource) {
		this.resource = resource;
	}

	@Override
	public void run() {
		for (int i = 0; i < 50; i++) {
			resource.popup();
		}
	}
}
--------------------------------------------------------
//共享资源对象(姓名 性别)
public class ProducerAndConsumer {
	private String name;
	private String gender;
	private boolean isEmpty = true;//表示共享资源对象是否为空的状态

	//push用于生产者向共享资源对象中存储数据
	synchronized public void push(String name, String gender) {
		//false:
		try {
			while (!isEmpty) {//当isEmpty为false的时候,不空,等着消费者来消费
				this.wait();//使用同步锁对象来调用当前线程释放同步锁,进入等待池中,只能被其他线程唤醒
			}
			this.name = name;
			Thread.sleep(10);
			this.gender = gender;

			isEmpty = false;//设置数据不为空

			this.notify();//唤醒一个消费者
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	//消费者从共享资源对象中取出数据
	synchronized public void popup() {
		try {
			while (isEmpty)//true时候,等待着生产者进行生产
			{
				this.wait();
			}
			//消费开始
			Thread.sleep(10);
			System.out.println(this.name + " " + this.gender);
			isEmpty = true;
			this.notify();//唤醒一个生产者
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
--------------------------------------------------------
//测试类
public class DebugDemo {
	public static void main(String[] args) {
		ProducerAndConsumer resource = new ProducerAndConsumer();
		new Thread(new Producer(resource)).start();
		new Thread(new Consumer(resource)).start();
	}
}

wait():执行该方法的线程对象释放同步锁,JVM把该线程放到等待池中,等待其他的线程唤醒该线程。
notify():执行该方法的线程唤醒在等待池中等待的任意一个线程,把线程转到锁池中等待。
notifyAll():执行该方法的线程唤醒在等待池中等待的所有的线程,把线程转到锁池中等待.
注意:上述方法只能被同步监听锁对象来调用,否则报错IllegalMonitorStateException。

2.线程的生命周期

线程可以处于以下几种状态:
1.新建状态:使用new创建一个线程对象,仅仅在堆内存中分配空间而已,在调用start方法之前根本没有启动。
2.就绪状态:线程对象调用了start方法之后,等待jvm的调度,此时线程依然没有运行。
3.运行状态:线程对象获得了JVM的调度,如果存在多个CPU,那么允许多个线程并行运行。
4.阻塞状态:正在运行的线程因为某些原因放弃PCU,此时JVM不会给线程分配CPU直到线程重新进入就绪状态。
5.等待状态:此状态只能被其他线程唤醒,此时使用wait方法,使得JVM把当前线程存在对象等待池中。
6.死亡状态。

3.线程的操作
①sleep操作
线程休眠:让执行的线程暂停一段时间,进入计时等待状态。
方法:static void sleep(long millis)
调用sleep后,当前线程放弃CPU,在指定时间段之内,sleep所在线程不会获得执行的机会。
此状态下的线程不会释放同步锁/同步监听器.
该方法更多的用于模拟网络延迟,让多线程并发访问同一个资源的错误效果更明显.
在开发中也会故意使用该方法。

public class Demo{
	public static void main(String[] args) throws InterruptedException {
		for(int i = 10; i > 0 ; i--) {
			System.out.println("倒计时" + i);
			Thread.sleep(1000);
		}
		System.out.println("OK");
	}	
}

②join操作
联合线程:
线程的join方法表示一个线程等待另一个线程完成后才执行。join方法被调用之后,线程对象处于阻塞状态。
有人也把这种方式称为联合线程,就是说把当前线程和当前线程所在的线程联合成一个线程。

class Join extends Thread {
	public void run() {
		for (int i = 0; i < 20; i++) {
			System.out.println("Join" + i);
		}
	}
}

public class Demo {
	public static void main(String[] args) throws InterruptedException {
		System.out.println("Begin");
		Join joinThread = new Join();
		for (int i = 0; i < 50; i++) {
			System.out.println("main" + i);
			if (i == 10) {
				joinThread.start();
			}
			if (i == 20) {
				joinThread.join();//强制执行该线程
			}
		}
		System.out.println("End");
	}
}

在这里插入图片描述
③后台线程
后台线程:在后台运行的线程,其目的是为其他线程提供服务,也称为“守护线程"。JVM的垃圾回收线程就是典型的后台线程。
特点:若所有的前台线程都死亡,后台线程自动死亡,前台线程没有结束,后台线程是不会结束的。

比如:GC线程为后台线程,主线程为前台线程。
前台线程创建的子线程默认也是前台的,后台同样。
但是也可以设置。

class DemonThread extends Thread {
	public void run() {
		for (int i = 0; i < 500; i++) {
			System.out.println(super.getName() + i);
		}
	}
}

public class Demo {
	public static void main(String[] args) throws InterruptedException {

		System.out.println(Thread.currentThread().isDaemon());//false说明主线程是前台线程
		for (int i = 0; i < 50; i++) {
			System.out.println("main" + i);
			if (i == 10) {
				DemonThread t = new DemonThread();
				t.setDaemon(true);//设置为后台线程
				t.start();//
			}
		}
	}
}

前台线程结束之后,后台线程也会随之结束。但是并不会立即结束。

线程优先级:
每个线程都有优先级,优先级的高低只和线程获得执行机会的次数多少有关,并非线程优先级越高的就一定先执行,哪个线程的先运行取决于CPU的调度。
MAX_PRIORITY=10,最高优先级
MIN_PRIORITY=1,最低优先级
NORM_PRIORITY=5,默认优先级

int getPriority() :返回线程的优先级。
void setPriority(int newPriority) : 更改线程的优先级。

每个线程都有默认优先级,主线程默认优先级为5,如果A线程创建了B线程,那么B线程和A线程具有相同优先级.
注意:不同的操作系统支持的线程优先级不同的,建议使用上述三个优先级,不要自定义.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值