Java多线程编程应用实例
6247字,阅读需时21分钟

文章导读

经过前面的学习,现在已经了解了多线程概念、Thread类的应用、多线程数据同步存在的问题及解决方法。本文给出一个多线程编程实例应用实例,通过实例的学习,可以灵活地把多线程知识应用到实际编程中,解决在项目开发过程中遇到的多线程编程问题。


在进入案例之前,先了解一下实现Java同步机制的几个方法,Java.lang.object类提供了wati()、notify()、notifyAll()方法,它们与synchronized关键字结合使用,可以建立很多优秀的同步模型。

当synchronized修饰的方法或代码块中的wati()方法被调用时,当前线程将被中断运行,并且放弃该对象的锁。

当另外的线程执行了某个对象的notify()方法后,会唤醒在此对象等待池中的某个线程,使之成为可运行的线程。notifyAll()方法会唤醒所有等待这个对象的线程,使之成为可运行的线程。

下面来看一个比较经典的问题:生产者(Producer)和消费者(Consumer)问题。这个问题的解决就是通过灵活使用wati()、notify()、notifyAll()方法来实现的。

任务要求如下:

生产者将产品交给店铺,消费者从店铺取走产品,店铺一次只能存储固定数量的产品,如果生产者生产了过多产品,店铺会让生产者等一下,如果店中有空间存储产品了,再通知生产者继续生产;如果店中没有产品了,店铺会告诉消费者等一下,如果店中有产品了,再通知消费者来取走产品。

要实现上述任务要求,我们需要定义一个生产者线程类和消费者线程类。再建立一个全局数组作为存储产品的缓冲区。其控制过程是,生产者向缓冲区存入产品,消费者从缓冲区取走产品。当缓冲区满时,生产者必须阻塞,等待消费者取走产品后将其唤醒。当缓冲区空时,消费者被阻塞,等待生产者生产了产品后将其唤醒。

(1)定义产品类,产品包含一个产品标识的id属性。另外要在生产或消费时打印产品的详细内容,因此重写toString()方法,产品类的代码如下所示:

package com.milihua.product;
public class Product {
    int id;
    public  Product(int id)
    {
        this.id = id;
    }
   
    public String toString()
    {
        return "Product" + id;
    }
}

(2)定义店铺类,店铺一次只能持有10份产品,如果生产者生产的产品多余10分,则会让当前正在此对象上操作的线程等待。一个线程访问addProduct方法时,它已经拿到这个锁了,当遇到产品大于10份时,它会阻赛。如果没有大于10份,则继续生产产品,并且调用notify方法,叫醒一个正在当前这个对象上等待的线程。这里请注意,notify和wait一般是一一对应的。代码如下所示:

package com.milihua.product;
public class Shop {
   //默认为0个产品
   int nIndex = 0;
   Product[] pro = new Product[10];
  
   //产品交给店员
   public synchronized void addProduct( Product pd )
   {
       while( nIndex == pro.length )
       {
          try {
            //产品已满,稍后生产
            this.wait();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
      }
       //通知等待区的消费者可以取产品了
      this.notify();
      pro[nIndex] = pd;
      nIndex++;
   }
  
   //消费者从店员处取走产品
   public synchronized Product getProduct()
   {
       while(nIndex == 0)
       {
           try {
            this.wait();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
      }
       this.notify();
       nIndex--;
       return pro[nIndex];
   }
  }

(3)定义生产者线程类,生产者负责生产产品,每生产完一个产品,调用Thread类的sleep方法休眠一段时间,模拟生产过程。代码如下:

package com.milihua.product;
public class Producer implements Runnable{
     //引用shop类
    Shop  shop;
    public Producer(Shop  inShop)
    {
        this.shop = inShop;
    }
   
    @Override
    public void run() {
        // TODO Auto-generated method stub
        //生产产品,生产数量要大于店员能够存储的数量
        for( int i = 0; i < 15; i++ )
        {
            Product  pro = new Product(i);
            shop.addProduct(pro);
            System.out.println("生产了:" + pro);
            //模拟生产一件产品花费的时间
            try {
                Thread.sleep((long)(Math.random()*1000));
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
 
    }
 
}

(4)定义消费者线程类,消费者负责消费产品,消费者每消费完一个产品,调用Thread类的sleep方法休眠一段时间,模拟消费过程。代码如下:

package com.milihua.product;
public class Consumer implements Runnable {
    //引用shop类
    Shop  shop;
    public Consumer(Shop  inShop)
    {
        this.shop = inShop;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for( int i = 0; i < 15; i++ )
        {
            Product pd = shop.getProduct();
            System.out.println("消费了:" + pd);
            //模拟消费一件产品要花费的时间
            try {
                Thread.sleep((long)(Math.random()*1000));
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
           
        }
       
    }
 
}

(5)定义主线程类。代码如下:

package com.milihua.product;
public class MainTest {
 
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Shop  shop = new Shop();
        Thread t1 = new Thread(new Producer(shop));
        t1.start();
   
        Thread t2 = new Thread(new Consumer(shop));
        t2.start();
       
    }
 
}

主线程类首先实例化Shop对象,然后分别实例化生产者线程和消费者线程。程序输出结果如下图所示:

blob.png

图1 生产者消费者示例程序输出结果

文章小结

案例有两个线程类,分别是Producer类(生产者)和Consumer类(消费者)。Shop类(店铺)负责产品的购进(存储产品的数量有限)与销售,因此Shop类需要协调Producer类和Consumer类,当Producer类生产过多产品时,Shop类需要调用wait方法让Producer类不要再继续生产,同时调用notify方法通知消费者来取走产品(如果有正在等待产品的消费者)。反之亦然,当无产品可取时,Shop类需要调用wait方法让Consumer类等待产品,同时调用notify方法通知生产者继续生产产品。

我要评论
全部评论
郎宏林
授课老师
授课老师简介
项目经理,系统分析和架构师,从事多年中文信息处理技术。熟悉项目管理、擅长项目需求分析和设计、精通Java、C#、Python等编程语言。
下载APP

手机、电脑同步学

用微信或手机浏览器扫描二维码,即可下载APP。

  • 备案号:鲁ICP备15001146号
  • @1997-2018 潍坊米粒花网络技术有限公司版权所有