在现实应用中,很多时候需要让多个线程按照一定的次序来访问共享资源。例如,经典的生产者和消费者问题。
① 这类问题描述了这样一种情况,假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中的产品取走消费。如果仓库中没有产品,则生产者可以将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止。如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,知道仓库中再次放入产品为止。
② 显然,这是一个同步问题,生产者和消费者共享同一资源,并且,生产者和消费者之间彼此依赖,互为条件向前推进。
该如何变成程序来解决这个问题呢?
传统的思路是利用循环检测的方式来实现,通过重复检查某一个特定条件是否成立来决定线程的推进顺序。
比如,一旦生产者生产结束,它就继续利用循环检测来判断仓库中的产品是否被消费者消费,而消费者也是在消费结束后就会立即使用循环检测的方式来判断仓库中是否又放进产品。显然,这些操作是很耗CPU资源的,不值得提倡。
有没有更好的方法来解决这类问题呢?
Java提供了3个重要的方法巧妙解决线程间的通信问题。这3个方法分别是:wait()、notify()和notifyAll()。
① wait():可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,直到被再次唤醒。
② notify():可以唤醒等待队列中第一个等待同一共享资源的线程,并使该线程退出等待队列,进入可运行状态。
③ notifyAll():可以使所有正在等待队列中同一共享资源的线程从等待队列状态退出,进入可运行状态,此时,优先级最高的那个线程最先执行。
示例:生产者采摘5个苹果放入篮子中,消费者拿走篮子中的5个苹果后,生产者再采摘5个放入篮子…共进行4次。
代码如下:
1 //消费者线程
2 class Consumer extends Thread {
3 private Basket basket = null;
4
5 public Consumer(Basket basket) {
6 super();
7 this.basket = basket;
8 }
9
10 @Override
11 public void run() {
12 basket.popApple();
13 }
14
15 }
16
17 //生产者线程
18 class Productor extends Thread {
19 private Basket basket = null;
20
21 public Productor(Basket basket) {
22 super();
23 this.basket = basket;
24 }
25
26 @Override
27 public void run() {
28 basket.pushApple();
29 }
30
31 }
32
33 //篮子类
34 class Basket {
35 private LinkedList<Apple> basket = new LinkedList<Apple>();
36
37 // 放4轮苹果
38 public synchronized void pushApple() {
39 for (int i = 0; i < 20; i++) {
40 Apple apple = new Apple(i);
41 push(apple);
42 }
43 }
44
45 // 取4轮苹果
46 public synchronized void popApple() {
47 for (int i = 0; i < 20; i++) {
48 pop();
49 }
50 }
51
52 // 向篮子中放苹果
53 private void push(Apple apple) {
54 // 当篮子中存放了5个苹果就等待并通知消费者来消费
55 if (basket.size() == 5) {
56 try {
57 wait();
58 } catch (InterruptedException e) {
59 e.printStackTrace();
60 }// 等待并释放当前资源的锁
61 }
62 try {
63 Thread.sleep(500);
64 } catch (InterruptedException e) {
65 e.printStackTrace();
66 }
67 basket.addFirst(apple);
68 System.out.println("存放:" + apple.toString());
69 notify();// 通知消费者来消费
70 }
71
72 // 向篮子中取苹果
73 private void pop() {
74 // 当篮子中苹果为0时就等待并通知生产者来生产
75 if (basket.size() == 0) {
76 try {
77 wait();
78 } catch (InterruptedException e) {
79 e.printStackTrace();
80 }// 等待并释放当前资源的锁
81 }
82 try {
83 Thread.sleep(500);
84 } catch (InterruptedException e) {
85 e.printStackTrace();
86 }
87 Apple apple = basket.removeFirst();
88 System.out.println("吃掉:" + apple.toString());
89 notify();// 通知生产者来生产
90 }
91 }
92
93 // 苹果类
94 class Apple {
95 private int id;
96
97 public Apple(int id) {
98 this.id = id;
99 }
100
101 @Override
102 public String toString() {
103 return "苹果:" + (id + 1);
104 }
105 }
主方法:
1 Basket basket=new Basket();
2 Productor productor=new Productor(basket);
3 Consumer consumer=new Consumer(basket);
4 productor.start();
5 consumer.start();
运行结果:
生产者逐个生产5个苹果1-5;消费者逐个消费5个苹果5-1;
生产者逐个生产5个苹果6-10;消费者逐个消费5个苹果10-6;
生产者逐个生产5个苹果11-15;消费者逐个消费5个苹果15-11;
生产者逐个生产5个苹果16-20;消费者逐个消费5个苹果20-16;
三大数据库 mysql oracle sqlsever 更专业、更强悍、适合不同用户群体
【新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统】
A集成代码生成器 [正反双向(单表、主表、明细表、树形表,开发利器)+快速构建表单; QQ:313596790
freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面、建表sql脚本,处理类,service等完整模块
B 集成阿里巴巴数据库连接池druid;
数据库连接池 阿里巴巴的 druid。Druid在监控、可扩展性、稳定性和性能方面都有明显的优势
C 集成安全权限框架shiro ;
Shiro 是一个用 Java 语言实现的框架,通过一个简单易用的 API 提供身份验证和授权,更安全,更可靠
D 集成ehcache 分布式缓存 ;
是一个纯Java的进程内缓存框架,具有快速、精干等特点,广泛使用的开源Java分布式缓存。
E 集成微信接口开发; F 图片爬虫技术; G SQL 编辑器, 支持复杂sql语句,生成报表,可以导出excel;
H websocket及时通讯技术;(即时聊天、及时站内信并声音提醒、实时在线管理、websocket及时刷新页面);
相关推荐
### VC多线程——最好理解的讲义 #### 一、问题的提出 在软件开发过程中,特别是针对复杂的用户界面应用程序或需要处理大量数据的应用场景时,如何有效地利用计算机资源并提升程序执行效率成为了关键性问题。单一...
【C# 多线程】是C#编程中一种重要的技术,它允许程序在同一时间执行多个任务,提高程序的响应速度和效率。多线程在现代软件开发中扮演着核心角色,尤其是在用户界面(UI)应用程序中,可以实现异步操作,避免用户...
本文将详细讲解如何初识通信,并以多线程服务器的构建为例,来阐述相关技术点。 首先,理解多线程的概念至关重要。多线程是指在一个进程中可以同时执行多个线程,这样可以充分利用CPU资源,提高程序的执行效率。在...
多线程编程能够提高应用程序的效率和响应性,尤其是在进行耗时操作如网络通信、大数据计算或长时间的IO操作时。本篇文章将深入探讨MFC中的多线程开发,帮助初学者理解和掌握这一关键技能。 首先,我们需要了解多...
6. **线程通信与协作**: - 等待/通知(wait/notify)机制:用于线程间的同步,一个线程等待另一个线程的通知后才能继续执行。 - 条件变量:在特定条件下允许线程等待,条件满足时唤醒。 - 管道(Pipe)和队列:...
本实例“实例257——使用Win32 API创建、销毁线程——控制进度条”主要探讨了如何使用Win32 API来创建和管理线程,并通过进度条来展示线程执行的进度。这一技术在开发多任务或需要异步处理的应用程序时非常关键。 ...
标题"android——多线程"和描述"android——Handler与多线程应用范例"暗示我们将深入探讨如何在Android中使用Handler来管理多线程。 Android系统默认运行在一个单线程环境中,即主线程,也被称为UI线程。主线程主要...
Java多线程是Java编程中的一个重要领域,它允许程序同时执行多个任务,从而提高系统效率和资源利用率。在这个未完成的案例中,我们可能正在探讨如何在Java中创建和管理线程,以及处理多线程环境下的并发问题。下面是...
线程通信是指多个线程之间的数据交换和信息传递。常见的通信机制包括管道、套接字、消息队列等。 四、线程安全性 线程安全性是指多线程程序的正确性和可靠性。线程安全性的关键在于避免线程之间的竞争和冲突,确保...
5. **同步与通信**:在多线程环境中,线程间通信是必需的。MFC提供了各种同步机制,如CSemaphore、CCriticalSection和CMutex等,用于控制对共享资源的访问。同时,CWinThread类提供了PostThreadMessage()函数,可以...
多线程技术是一种编程方法,它允许在一个进程中同时运行多个执行单元,以提高程序的并发性和效率。在本文中,作者韩耀旭介绍了多线程编程的概念和在Windows环境下的实现,包括WinAPI和MFC的使用。 首先,文章通过一...
在多线程环境下,线程间的通信和同步至关重要。C++11引入了`std::mutex`(互斥锁)和`std::condition_variable`(条件变量)等工具,而wxWidgets也提供了相应的类,如`wxMutex`和`wxCondition`。这些同步原语用于...
本项目以"JAVA项目——多线程下载代码"为主题,使用Eclipse集成开发环境进行实现,适合于Java初学者或毕业设计实践。下面我们将深入探讨相关的Java多线程下载知识点。 1. **线程基础**:在Java中,线程是程序执行的...
在本项目"操作系统课程设计——简单多线程"中,我们将深入探讨多线程这一关键概念,以及它在操作系统中的实现。 多线程是指在一个进程中同时执行多个线程,每个线程都具有独立的执行路径,可以并行处理任务,提高...
这个名为"Java多线程的小例子——吃包子"的示例,旨在帮助开发者直观地理解多线程的工作原理。下面我们将深入探讨该示例所涉及的核心知识点。 首先,多线程通常涉及到以下几个关键概念: 1. **线程(Thread)**:...
在给定的标题“文件复制——多线程”中,我们可以推断出这个博客文章可能讨论的是如何利用多线程技术优化文件复制的过程。通常,这涉及到以下几个关键知识点: 1. **线程创建**:在Java或其他支持多线程的编程语言...
多线程是现代计算机编程中的一个重要概念,尤其在操作系统如Windows这样的多任务环境中,多线程使得程序能够并发执行多个任务,从而充分利用系统的计算资源,提高程序的响应速度和效率。在C#编程中,多线程机制是...
本教程“Visual C++高级编程技术——MFC与多线程篇”将深入探讨这两个关键概念。 MFC是C++面向对象编程的一个重要框架,它基于Windows API,将复杂的Win32 API函数封装为易于理解和使用的类。MFC包含了一系列的类,...
线程间通信是多线程编程中的核心概念,它允许不同线程之间交换信息和协调工作。当一个程序中存在多个并发执行的线程时,它们可能需要共享数据或者互相通知事件的发生,这就需要线程间通信机制。下面将详细讨论几种...