java多线程中的生产者消费者

时间:2013-11-06 01:54:11

标签: java multithreading consumer producer

我正在尝试在java中实现Producer Consumer问题。我正在使用循环缓冲区(循环数组)来让Producer将项目插入缓冲区。以下是我的代码:

import java.util.*;
import java.io.*;

public class Buffer
{
    String a[];
    int front, rear;

    public Buffer(int size)
    {
            a = new String[size];
            front = rear = -1;
    }

    public boolean insert(String dataitem)
    {
            int p;
            p = (rear+1) % a.length;

            if(p==front)
            {
                    System.out.println("Buffer full");
                    return false;
            }
            else
            {       rear = p;
                    a[rear] = dataitem;
                    if(front == -1)
                            front = 0;
                    return true;
            }
    }

    public boolean empty()
    {
            if(front == -1)
                    return true;
            else
                    return false;
    }

    public String delete()
    {
            String result = a[front];
            if(front == rear)
                    front = rear = -1;
            else
                    front = (front +1)%a.length;
            return result;
    }

    public void display()
    {
            if(front == -1)
                    System.out.println("Buffer empty");
else
            {
                    System.out.println("Buffer elements are:");
                    int i= front;

                    while(i!= rear)
                    {
                            System.out.println(a[i]);
                            i = (i+1)%a.length;
                    }
                    System.out.println(a[i]);
            }
    }


    public static void main(String[] args)
    {
            int size = Integer.parseInt(args[0]);

            Buffer b = new Buffer(size);
            int ch;
            String dataitem, msg;

            Thread prod = new Thread(new Producer(b, size));
            Thread cons = new Thread(new Consumer(b, size));

            prod.start();
            cons.start();
    }

}

class Producer extends Thread
{
    Buffer b;
    int size;

    public Producer(Buffer b, int size)
    {
            this.b = b;
            this.size = size;
    }

    public void run()
    {
            while(true)
            {
                    synchronized(b)
                    {
                    for(int i = 1; i <= size; i++)
                    {
                            try
                            {       String dataitem = Thread.currentThread().getId()+"_"+i;
                                    boolean bool = b.insert(dataitem);
                                    //b.notifyAll();
if(bool)
                                            System.out.println("Successfully inserted "+dataitem);
                                    b.notifyAll();
                                    Thread.sleep(2000);
                            }
                            catch(Exception e)
                            {       e.printStackTrace();
                            }
                    }

            }
            }
    }
}

class Consumer extends Thread
{
    Buffer b;
    int size;

    public Consumer(Buffer b, int size)
    {
            this.b = b;
            this.size = size;
    }

    public void run()
    {
            while(b.empty())
            {
                    synchronized(b)
                    {
                            try
                            {
                                    System.out.println("Buffer empty");
                                    b.wait();
                            }
                            catch(Exception e)
                            {       e.printStackTrace();
                            }
                    }
            }

            synchronized(b)
            {
                    b.notifyAll();
                    String dataitem = b.delete();
                    System.out.println("Removed "+dataitem);
            }

    }
}

生产者正在成功地将数据项插入缓冲区。但它们并没有被消费者消费。

执行程序时,我得到以下输出。

Successfully inserted 11_1
Successfully inserted 11_2
Buffer full
Buffer full
Buffer full
Buffer full
Buffer full
Buffer full

我的问题是如何让消费者使用缓冲区中的项目?

1 个答案:

答案 0 :(得分:1)

主要问题是synchronized中的Producer块太宽。永远不会让Consumer获得锁定

首先缩小范围,例如......

while (true) {
    for (int i = 1; i <= size; i++) {
        try {
            String dataitem = Thread.currentThread().getId() + "_" + i;
            boolean bool = b.insert(dataitem);
            //b.notifyAll();
            if (bool) {
                System.out.println("Successfully inserted " + dataitem);
            }
            synchronized (b) {
                b.notifyAll();
            }
            Thread.sleep(2000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

您也可以考虑自行同步ing insertdelete方法。我个人很想使用内部锁,但你可以简单地synchronize方法本身,例如...

public synchronized boolean insert(String dataitem) {...}

public synchronized String delete() {...}

就目前而言,你的Consumer只会从缓冲区读取一个值,但我会让你想出那个;)

作为旁注,我可能会将等待和通知功能直接放在Buffer中,这样每当您尝试delete一个值时,它都会在delete内等待Buffer不为空的方法,允许insert方法自行发出通知......但那就是我;)

同样,我可能会考虑阻止insert方法,直到有更多空间,但这将取决于您希望如何实现它:P

<强>更新

非常基本上,这将开始提供您正在寻找的结果......

public class ProducerConsumer {

    public static void main(String[] args) {
        new ProducerConsumer();
    }

    public ProducerConsumer() {
        int size = 5;

        Buffer b = new Buffer(size);

        Thread prod = new Thread(new Producer(b, size));
        Thread cons = new Thread(new Consumer(b, size));

        prod.start();
        cons.start();
    }

    public class Buffer {

        String a[];
        int front, rear;

        public Buffer(int size) {
            a = new String[size];
            front = rear = -1;
        }

        public synchronized boolean insert(String dataitem) {
            int p;
            p = (rear + 1) % a.length;

            if (p == front) {
                System.out.println("Buffer full");
                return false;
            } else {
                rear = p;
                a[rear] = dataitem;
                if (front == -1) {
                    front = 0;
                }
                return true;
            }
        }

        public boolean empty() {
            return front == -1;
        }

        public synchronized String delete() {
            String result = a[front];
            if (front == rear) {
                front = rear = -1;
            } else {
                front = (front + 1) % a.length;
            }
            return result;
        }

        public void display() {
            if (front == -1) {
                System.out.println("Buffer empty");
            } else {
                System.out.println("Buffer elements are:");
                int i = front;

                while (i != rear) {
                    System.out.println(a[i]);
                    i = (i + 1) % a.length;
                }
                System.out.println(a[i]);
            }
        }

    }

    class Producer extends Thread {

        Buffer b;
        int size;

        public Producer(Buffer b, int size) {
            this.b = b;
            this.size = size;
        }

        public void run() {
            int i = 0;
            while (true) {
                try {
                    String dataitem = Thread.currentThread().getId() + "_" + ++i;
                    boolean bool = b.insert(dataitem);
                    if (bool) {
                        System.out.println("Successfully inserted " + dataitem);
                    }
                    synchronized (b) {
                        b.notifyAll();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
    }

    class Consumer extends Thread {

        Buffer b;
        int size;

        public Consumer(Buffer b, int size) {
            this.b = b;
            this.size = size;
        }

        public void run() {

            while (true) {

                while (b.empty()) {
                    synchronized (b) {
                        try {
                            System.out.println("Buffer empty");
                            b.wait();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }

                String dataitem = null;
                synchronized (b) {
                    dataitem = b.delete();
                }
                    System.out.println("Removed " + dataitem);
            }
        }
    }
}