前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaSE开发技术线程的通信

JavaSE开发技术线程的通信

作者头像
程序狗
发布2021-12-13 14:24:17
2410
发布2021-12-13 14:24:17
举报
文章被收录于专栏:大数据知识

l wait() 与 notify() 和 notifyAll()

Ø wait():令当前线程挂起并放弃CPU、同步资源,使别的线程可访问并修改共享资源,而当前线程排队等候再次对资源的访问

Ø notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待

Ø notifyAll ():唤醒正在排队等待资源的所有线程结束等待.

Java.lang.Object提供的这三个方法只有在synchronized方法或synchronized代码块中才能使用,否则会报 java.lang.IllegalMonitorStateException异常

wait() 方法

在当前线程中调用的方法: 对象名.wait()

使当前线程进入等待(某对象)状态 ,直到另一线程对该对象发出 notify (或notifyAll) 为止。

调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)

调用此方法后,当前线程将释放对象的监控权 ,然后进入等待

在当前线程被notify后,要重新获得监控权,然后从断点处继续代码的执行。

notify()/notifyAll()

在当前线程中调用的方法: 对象名.notify()

功能:唤醒等待该对象监控权的一个线程。

调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)

例 题

使用两个线程打印 1-100. 线程1, 线程2 交替打印

代码语言:javascript
复制
class Communication implements Runnable {
int i = 1;

public void run() {
while (true) {
synchronized (this) {
notify();
if (i <= 100) {
System.out.println(Thread.currentThread().getName() + ":" + i++);
} else
break;
try {
wait();
} catch (InterruptedException e) {
}
}
}
}
}

经典例题:生产者/消费者问题

生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,java培训店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。

这里可能会出现两个问题:

Ø 生产者比消费者快时,消费者会漏掉一些数据没有取到。

Ø 消费者比生产者快时,消费者会取相同的数据。

代码语言:javascript
复制
public class TestProduct {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Thread productorThread = new Thread(new Productor(clerk));
Thread consumerThread = new Thread(new Consumer(clerk));
productorThread.start();
consumerThread.start();
}
}

class Clerk { // 售货员
private int product = 0;

public synchronized void addProduct() {
if (product >= 20) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
product++;
System.out.println("生产者生产了第" + product + "个产品");
notifyAll();
}
}

public synchronized void getProduct() {
if (this.product <= 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println("消费者取走了第" + product + "个产品");
product--;
notifyAll();
}
}
}

class Productor implements Runnable { // 生产者
Clerk clerk;

public Productor(Clerk clerk) {
this.clerk = clerk;
}

public void run() {
System.out.println("生产者开始生产产品");
while (true) {
try {
Thread.sleep((int) Math.random() * 1000);
} catch (InterruptedException e) {
}
clerk.addProduct();
}
}
}

class Consumer implements Runnable { // 消费者
Clerk clerk;

public Consumer(Clerk clerk) {
this.clerk = clerk;
}

public void run() {
System.out.println("消费者开始取走产品");
while (true) {
try {
Thread.sleep((int) Math.random() * 1000);
} catch (InterruptedException e) {
}
clerk.getProduct();
}
}
}

线程池

系统启动一个新线程的成本是比较高的,因为它涉及与os交互。这种情况下,系统启动时即创建大量空闲的线程,就可以很好地提高性能,尤其是当程序需要创建大量生存期很短暂的线程时。

除此之外,使用线程池可以有效地控制系统中并发线程的数量。避免因并发创建的线程过多,导致系统性能下降,JVM崩溃。

Java 5以前,需要手动创建自己的线程池;Java 5开始,新增了Executors工厂类产生线程池。

使用线程池执行线程任务的步骤如下:

1.调用Executors 类的静态方法newFixedThreadPool(int nThreads),创建一个可重用的、具有固定线程数的线程池ExecutorService对象

2.创建Runnable实例,作为线程执行任务

3.调用ExecutorService对象的submit()提交Runnable实例

4.调用ExecutorService对象的shutDown()方法关闭线程池。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • wait() 方法
  • notify()/notifyAll()
  • 例 题
  • 线程池
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档