x286212455的个人空间 https://www.eechina.com/space-uid-142968.html [收藏] [复制] [RSS]

博客

生产者与消费者-钛极OS(TiJOS)系统中的多线程

已有 1157 次阅读2018-5-4 13:25 |个人分类:物联网| Java

钛极OS(TiJOS)支持Java中标准的线程Thread和Runnable, 符合Java标准, 线程可以大大简化许多类型的应用程序开发,但过度使用线程可能会影响程序的性能及其可维护性, 一般建议用在不阻塞整个程序的情况下执行阻塞 I/O, 如等待网络数据等等。

钛极OS(TiJOS)中的线程与Java标准兼容, 因此只需参考Java中Thread 和Runable类编程方式即可快速应用。

线程优先极

建议所有线程使用默认优先级,否则有可能导致低优先级的线程没有机会执行。

线程创建、启动

线程一般通过 Thread 构造器或实例化Thread的子类来创建并通过start()方法启动

/**
* 扩展Thread类实现多线程程序
*/
public class CounterThread extends Thread{

    
public CounterThread(String name) {
        
super(name);
    
}

    
public void run() {
        
int i = 0;
        
while(true)
        
{
          
i ++ ;
          
System.out.println(this.getName() + " count: " + i);
          
try {
               
Thread.sleep(100);
           
} catch (InterruptedException e) {
               
e.printStackTrace();
           
}
        
}
    
}

    
public static void main(String[] args) {
        
Thread t1 = new CounterThread("thread 1");
        
Thread t2 = new CounterThread("thread 2");
        
t1.start();
        
t2.start();
    
}
}

输出结果:

thread_output

源码请参考:CounterThread.java

线程结束

run方法结束或有未捕获的异常发生后,线程也就结束了

经典生产者与消费者问题

生产者与消费者问题是线程同步里边一个很经典的问题, 用通俗的语言来描述

  1. 一群生产者不断的生产产品,并将产品放到一个仓库里边;同时一群消费者不断从仓库里边消费产品
  2. 仓库的容量是有限的。如果仓库满了,生产者不能再往仓库放产品,必须进入等待状态。等待产品被消费者拿走了,再往仓库放产品
  3. 同样,如果仓库空了,消费者也必须进入等待状态, 等待生产者往里边放产品,再将消费者唤醒

在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(是类、函数、线程、进程等), 产生数据的模块,就形象地称为生产者; 而处理数据的模块,就称为消费者, 数据保存的位置(缓存区, 文件等) 即为仓库, 仓库作为一个中介, 生产者把数据放入,而消费者从中取出.

解决方案

在Java中生产者与消费者的处理方式一般遵循如下原则:



生产者与消费者模型 Java中的解决方法
条件1 同一时间内只能有一个生产者生产 生产方法加锁sychronized
条件2 同一时间内只能有一个消费者消费 消费方法加锁sychronized
条件3 生产者生产的同时消费者不能消费 生产方法加锁sychronized
条件4 消费者消费的同时生产者不能生产 消费方法加锁sychronized
条件5 共享空间空时消费者不能继续消费 消费前循环判断是否为空,空的话将该线程wait,释放锁允许其他同步方法执行
条件6 共享空间满时生产者不能继续生产 生产前循环判断是否为满,满的话将该线程wait,释放锁允许其他同步方法执行





TiJOS 例程代码

产品类, 用于表示需要处理的数据对象

//产品
class Product
{
   
private int id;

   
Product(int id){
       
this.id = id;
   
}

   
public String toString(){
       
return "Product :" + id;
   
}
}

仓库类, 用于存储生产出的产品,消费时从仓库取出,一般用集合实现, 此类中push为生产方法, 生产的产品通过该方法将产品放入仓库; pop为消费方法,从仓库中取出产品进行处理.

生产者线程和消费者线程共享同一个仓库,因此在访问仓库时需要同步。

产品仓库
class Warehouse
{
   
Product productStore[] = new Product[6];
   
int index = 0;

   
/**
    * 生产方法.
    * 该方法为同步方法,持有方法锁
    * 首先循环判断满否,满的话使该线程等待,释放同步方法锁,等待消费;
    * 当不满时首先唤醒正在等待的消费方法,但是也只能让其进入就绪状态,
    * 等生产结束释放同步方法锁后消费才能持有该锁进行消费
    *
    * @param p 产品
    * @return 
    */

   
public synchronized void push(Product p){
       
try{
           
while(index == productStore.length){
               
System.out.println("[Produce] Warehouse: Full - wait consumer");
               
this.wait();
           
}
           
this.notify();

       
}catch(InterruptedException e){
           
e.printStackTrace();
       
}catch(IllegalMonitorStateException e){
           
e.printStackTrace();
       
}  

       
productStore[index] = p;
       
index++;
       
System.out.println("[Produce]:" + p + " [Total]: " + index);

   
}

   
/**
    * 消费方法
    * 该方法为同步方法,持有方法锁
    * 首先循环判断空否,空的话使该线程等待,释放同步方法锁,允许生产;
    * 当不空时首先唤醒正在等待的生产方法,但是也只能让其进入就绪状态
    * 等消费结束释放同步方法锁后生产才能持有该锁进行生产
    * @return 
    */
   
public synchronized Product pop(){
       
try{
           
while(index == 0){
               
System.out.println("[Consume] Warehouse: Empty - wait producer");
               
this.wait();
           
}
           
this.notify();

       
}catch(InterruptedException e){
           
e.printStackTrace();
       
}catch(IllegalMonitorStateException e){
           
e.printStackTrace();
       
}

       
index--;
       
System.out.println("[Consume]: " + productStore[index] + "[Total]: " + index);
       
return productStore[index];
   
}
}

生产者线程,负责产品的生产过程,将生产的产品放入到仓库中

/**
*
* 生产者线程
*
*/
class ProducerTask implements Runnable
{
   
Warehouse wh;
   
ProducerTask(Warehouse w){
       
this.wh = w;
   
}

   
//生产过程
   
public void run(){
       
for(int i = 0;i < 20;i++){ Product m = new Product(i);
           
wh.push(m);
           
try{
               
Thread.sleep((int)(Math.random()*500));
           
}catch(InterruptedException e){
               
e.printStackTrace();
           
}
       
}
   
}
}

消费者线程, 负责产品的消费,将仓库中的产品取出

/**
*
* 消费者线程
*
*/
class ConsumerTask implements Runnable
{
   
Warehouse wh = null;
   
ConsumerTask(Warehouse w){
       
this.wh = w;
   
}

   
//消费过程
   
public void run(){
       
for(int i = 0;i < 20;i++){ Product p = wh.pop();
           
try{
               
Thread.sleep((int)(Math.random()*1000));
           
}catch(InterruptedException e){
               
e.printStackTrace();
           
}
       
}
   
}
}

主程序, 启动生产者和消费者线程进行并行处理

//生产者-消费者
class  ProducerConsumer
{
   
public static void main(String[] args)
   
{
       
Warehouse w = new Warehouse();
       
ProducerTask p = new ProducerTask(w);
       
ConsumerTask c = new ConsumerTask(w);
       
Thread tp = new Thread(p);
       
Thread tc = new Thread(c);
       
tp.start();
       
tc.start();
   
}
}

编译下载后,在TiKit上的运行结果如下:

producer_consumer_output

相关源码请参考ProducerConsumer.java


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 立即注册

关于我们  -  服务条款  -  使用指南  -  站点地图  -  友情链接  -  联系我们
电子工程网 © 版权所有   京ICP备16069177号 | 京公网安备11010502021702
返回顶部