`
grape1360
  • 浏览: 3417 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

线程同步

阅读更多
生产者消费者问题是多线程中一个典型的案例.  其主要逻辑是 生产者生产产品, 将将生产的产品放入到产品队列中供消费者队列. 消费者再从产品队列中取得产品进行消费.
需要注意的是:
  1) 当产品队列中产品的数量达到饱和状态, 生产者停止生产进入等待状态, 等待消费者从队列中取走产品时唤醒生产者继续生产.
  2) 当产品队列中产品的数量不足时, 消费者停止消费进入等待状态, 等待生产者再往队列中存入产品时唤醒消费者继续消费.

下面是具体代码
主类MainProcesser:

import java.io.DataInputStream;
import java.io.IOException;

import com.fji.consumer.Consumer;
import com.fji.producer.Producer;
import com.fji.util.ProductQueue;


/**
 * 主类 
 * @author mOnsoOn
 *
 */
public class MainProcesser {
	private Producer pro;
	private Consumer con;
	
	public MainProcesser(Producer pro, Consumer con) {
		this.pro = pro;
		this.con = con;
	}
	
	public static void main(String[] args) {
		ProductQueue q = new ProductQueue();
		Producer p = new Producer(q);
		Consumer c = new Consumer(q);
		MainProcesser process = new MainProcesser(p,c);
		process.startThread();
		process.receiveKeyboard();
	}
	
	private void startThread() {
		pro.start();
		con.start();
	}
	
	private void addConsumerSpeed() {
		pro.slowProduceSpeed();
		con.addConsumerSpeed();
	}
	
	private void addProducerSpeed() {
		pro.addProduceSpeed();
		con.slowConsumerSpeed();
	}
	
	/**
	 * 可以通过键盘事件对生产者消费者执行速度进行控制
	 * quit: 系统退出
	 * 1: 增加生产速度
	 * 2: 增加消费速度
	 */
	private void receiveKeyboard() {
		for(;;) {
			System.out.println("接收键盘事件(quit:退出 1:增加生产速度 2:增加消费速度)");
			DataInputStream dis = new DataInputStream(System.in);
			try {
				String event = dis.readLine();
				System.out.println("接收到键盘事件: " + event);
				if(event.equalsIgnoreCase("quit")) {
					System.out.println("系统退出");
					System.exit(0);
				}
				else if(event.equalsIgnoreCase("1")) {
					addProducerSpeed();
				}
				else if(event.equalsIgnoreCase("2")) {
					addConsumerSpeed();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				Thread.sleep(20);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
		}
	}

}



生产者Producer :
package com.fji.producer;


import com.fji.util.Product;
import com.fji.util.ProductQueue;

/**
 * 生产者类
 * @author mOnsoOn
 *
 */
public class Producer extends Thread {
	private ProductQueue queue;
	public static final int CAPACITY = 20;
	private int produce_speed = 3000;
	
	public Producer(ProductQueue queue) {
		this.queue = queue;
	}
	
	@Override
	public void run() {
		System.out.println("<生产者> 生产者开始生产产品");
		for(;;) {
			//生产者生成产品以后放入到队列中供消费者使用
			Product p = this.createProduct();
			queue.put(p);
			System.out.println("<生产者> 生产者新生产了一个产品: " + p);
			try {
				System.out.println("<生产者> 生产者休息" + produce_speed + " 毫秒");
				Thread.sleep(produce_speed);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void addProduceSpeed() {
		System.out.println("<生产者> 加速");
		this.produce_speed = this.produce_speed - 100;
	}
	
	public void slowProduceSpeed() {
		System.out.println("<生产者> 减速");
		this.produce_speed = this.produce_speed + 100;
	}
	
	private Product createProduct() {
		Product p = new Product("产品");
		return p;
	}

}



消费者Consumer :
package com.fji.consumer;

import com.fji.util.Product;
import com.fji.util.ProductQueue;

/**
 * 消费者
 * @author mOnsoOn
 *
 */
public class Consumer extends Thread {
	private ProductQueue queue;
	public static final int CAPACITY = 5;
	private int consume_speed = 3000;
	
	public Consumer(ProductQueue queue) {
		this.queue = queue;
	}
	
	@Override
	public void run() {
		System.out.println("<消费者>开始消费");
		for(;;) {
			//消费者从队列中取产品
			Product p = queue.get();
			System.out.println("<消费者> 消费者消费了一个产品" + p.toString());
			try {
				System.out.println("<消费者> 消费者休息" + consume_speed + " 毫秒");
				Thread.sleep(consume_speed);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void addConsumerSpeed() {
		System.out.println("<消费者>加速");
		this.consume_speed = this.consume_speed - 100;
	}
	
	public void slowConsumerSpeed() {
		System.out.println("<消费者>减速");
		this.consume_speed = this.consume_speed + 100;
	}
	
}



产品队列ProductQueue :

package com.fji.util;

import java.util.concurrent.ConcurrentLinkedQueue;

import com.fji.consumer.*;
import com.fji.producer.*;

/**
 * 产品队列
 * @author mOnsoOn
 *
 */
public class ProductQueue {
	private ConcurrentLinkedQueue<Product> queue;
	
	public ProductQueue() {
		queue = new ConcurrentLinkedQueue<Product>();
	}
	
	/**
	 * 生产者将产品放入到队列中, 当队列中产品已满时, 生产者进入等待状态
	 * @param product 产品
	 * @return
	 */
	public synchronized boolean put(Product product) {
		if(this.size() >= Producer.CAPACITY ) {
			System.out.println("<生产者> 产品队列已满, 生产者暂停生产");
			try {
				//当队列中产品达到一定数量以后, 生产者暂停, 等待消费者唤醒
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("<生产者> 生产者继续生产产品");
		}
		//生产者继续生产同时, 唤醒消费者继续消费
		notifyAll();
		return queue.offer(product);
	}
	
	/**
	 * 消费者从队列中取得产品, 当队列中产品不足时,消费者进入等待状态
	 * @return
	 */
	public synchronized Product get() {
		if(this.size() <= Consumer.CAPACITY) {
			System.out.println("<消费者>产品池中产品数量不足, 消费者暂停消费");
			try {
				//队列中产品数量不足, 消费者暂停,等待生产者唤醒
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("<消费者>消费者继续消费");
		}
		//消费者继续消费同时, 唤醒生产者继续生产
		notifyAll();
		return queue.poll();
	}
	
	/**
	 * 返回队列中产品数量
	 * @return
	 */
	private synchronized int size() {
		return queue.size();
	}
}



产品Product :

package com.fji.util;

public class Product {
	private String name;
	private int id;
	private static int sid=0;
	
	public Product(String name) {
		this.name = name;
		id = Product.sid++;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	public int getId() {
		return id;
	}

	@Override
	public String toString() {
		return "Product:(name=" + name + ", id=" + id + ")";
	}
	
	

}



分享到:
评论

相关推荐

    vc++中的线程锁(线程锁保持线程同步)

    在VC++编程环境中,线程同步是一个至关重要的概念,特别是在多线程程序设计中,以确保并发执行的线程能够安全地访问共享资源,避免数据竞争和其他潜在的问题。本篇文章将详细探讨线程锁在VC++中的应用,以及如何通过...

    线程同步的五种方法

    线程同步是多线程编程中的重要概念,用于协调多个并发执行的线程,确保它们在访问共享资源时不会产生竞态条件或数据不一致性。在Windows编程中,提供了多种线程同步机制,包括互斥量、临界区、原子操作、事件以及...

    操作系统线程同步实验报告

    操作系统线程同步是多线程编程中的核心概念,旨在确保并发执行的线程在访问共享资源时不会引发数据不一致性和竞态条件。本实验报告详细探讨了这一主题,通过一个简单的银行账户转账的示例来揭示临界区问题及其解决...

    线程同步的四种方式

    在多线程编程中,线程同步是一种控制多个线程并发执行时访问共享资源的方式,以避免数据不一致和死锁等问题。以下是对线程同步的四种主要方式的详细解释: 1. **事件(Event)** 事件是Windows API提供的一种线程...

    线程同步解决火车站售票问题

    在这个“线程同步解决火车站售票问题”的例子中,我们可以通过线程同步机制来实现售票的有序、无冲突的过程。 首先,我们需要理解问题的核心:10个售票处(线程)需要共享1000张票(资源),并且每卖出一张票,必须...

    操作系统实验多线程同步(含C++源代码)

    操作系统中的多线程同步是一个关键概念,特别是在并发编程中,它涉及到如何协调多个线程以避免数据不一致性和竞态条件。在这个实验中,我们关注的是C++编程语言中的实现,以及操作系统如何处理线程的优先级。 首先...

    简单实现多线程同步示例(模拟购票系统)

    本示例“简单实现多线程同步示例(模拟购票系统)”旨在通过一个具体的实例,帮助开发者理解如何在Java中创建并管理多线程以及如何实现线程同步,确保数据的一致性和正确性。 首先,我们要明确多线程的基本概念。在...

    VC++线程同步实例

    在编程领域,线程同步是多线程编程中的一个重要概念,它确保了多个线程在访问共享资源时的正确性和一致性。在这个“VC++线程同步实例”中,我们将探讨如何利用VC++(Visual C++)来实现线程间的同步,以避免数据竞争...

    操作系统线程同步算法

    操作系统中的线程同步是多线程编程中一个关键的概念,它确保了多个线程在访问共享资源时的正确性,防止数据竞争和其他并发问题。在Windows操作系统中,提供了多种线程同步机制,如临界区、事件、信号量以及互斥量等...

    Delphi多线程同步的例子

    本文将深入探讨Delphi中的多线程和线程同步,并以"SortThreads"和"delphi-thread-gui"这两个示例项目为例,讲解如何在实践中应用这些概念。 1. **多线程**:多线程允许应用程序同时执行多个独立的任务,提高程序的...

    多线程及线程同步

    然而,多线程环境下也带来了一些问题,尤其是资源竞争和数据一致性问题,这些问题需要通过线程同步机制来解决。本文将详细介绍如何通过临界区、互斥内核对象、事件内核对象和信号量内核对象来实现线程同步。 1. ...

    Java多线程同步.pdf

    "Java多线程同步.pdf" Java多线程同步是指在Java语言中,如何使用synchronized关键字和其他同步机制来确保多线程程序的正确执行。在Java语言中,synchronized关键字用于对方法或者代码块进行同步,但是仅仅使用...

    线程同步小例子

    在编程领域,线程同步是多线程编程中的一个核心概念,它涉及到如何有效地管理和协调多个并发执行的线程,确保它们能正确地共享资源,避免数据竞争和死锁等问题。这个“线程同步小例子”是基于孙鑫先生著作中的示例...

    操作系统实验 多线程同步与互斥 java编写 有界面

    操作系统实验是计算机科学教育中的重要组成部分,它帮助学生理解和掌握操作系统的基本原理,特别是多线程同步与互斥的概念。在Java编程环境下,这些概念可以通过实际的代码实现来深入理解。 多线程是现代操作系统中...

    多线程的批量线程同步解决方案

    "多线程的批量线程同步解决方案"这个标题暗示我们探讨的是如何在多线程环境下有效地管理和同步多个任务,确保数据一致性与程序正确性。下面将详细阐述相关知识点。 一、多线程基础 多线程是指在一个进程中同时执行...

    Jni多线程同步事例

    在本例“Jni多线程同步事例”中,我们将探讨如何在JNI层面上实现多线程同步,特别是在一个生产者-消费者模型的场景下。 生产者-消费者模型是一种经典的并发问题,它涉及到两个或多个线程之间的协作。在该模型中,...

    c#线程同步的典型例子

    C#线程同步是多线程编程中的一个重要概念,它涉及到如何控制多个线程对共享资源的访问,以避免数据不一致性和竞态条件。在C#中,线程同步通常用于确保在某一时刻只有一个线程可以访问特定的代码块或资源,从而保证...

Global site tag (gtag.js) - Google Analytics