我的线程不会醒来

时间:2016-11-15 18:22:24

标签: java multithreading

已编辑:从答案中添加了解决方案。

所以我构建了经典的多线程程序,其中2个线程,生产者和消费者从同一个列表中读取。我确实让它工作我让我的消费者线程不断轮询列表,但这是无效的,并导致我的一些其他问题。所以我想我会尝试等待,然后通知。我的两个线程都在下面的代码中使用相同的缓冲区引用:

缓冲液:

public class Buffer {

    private Queue<Character> result;

    public Buffer() {
        System.out.println("Buffer");
        result = new LinkedList<Character>();
    }

    public void addChar(char c) {
        result.add(c);
    }

    public char readChar() {
        return (char) result.remove();
    }

    public boolean isEmpty() {
        return result.isEmpty();
    }

}

生产者

public class Producer implements Runnable {

private Buffer buffer;
private Callback callback;
private String input;

public Producer(Callback callback, Buffer buffer, String input) {
    this.callback = callback;
    this.buffer = buffer;
    this.input = input;
}

@Override
public void run() {
    System.out.println("producer started");
       synchronized (buffer) {
            char[] array = input.toCharArray();
            for (int i = 0; i < array.length; i++) {
                buffer.addChar(array[i]);
                System.out.println("Adding--------- data");
                callback.returnData("Added " + array[i]);
                buffer.notifyAll();
            }
        }
    }
}

消费

public class Consumer implements Runnable {

    private Callback callback;
    private Buffer buffer;

    public Consumer(Callback callback, Buffer buffer) {
        this.callback = callback;
        this.buffer = buffer;
    }

    @Override
public void run() {
    System.out.println("consumer started");
    try {
        synchronized (buffer) {
            while (true) {
                if (buffer.isEmpty()) {
                    System.out.println("Queue is empty ");
                    buffer.wait();
                }
                if (!buffer.isEmpty()) {
                    System.out.println("Reading data");
                    callback.returnData(" Retrieved " + String.valueOf(buffer.readChar()));
                } else {
                    callback.returnData("Waiting");
                }
            }
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
}

我想要做的是每次生产者线程添加一个元素时,它应该通知我的Consumer线程它现在可以从缓冲区中读取。问题是,在添加所有数据之前,它不会被唤醒。这是我在控制台上的结果:

buffer initiated
producer started
consumer started
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Queue is empty 

现在,我真正想要的是:&#34;添加数据&#34;,&#34;读取数据&#34;,&#34;添加数据&#34;等等。

2 个答案:

答案 0 :(得分:1)

您应该在共享对象上进行同步(在缓冲区上调用wait和notify)

检查以下代码 -

//tabelview cell register 

let nib: UINib = UINib(nibName: "ItemTableViewCell", bundle: nil) 

tableViewItemList.register(nib, forCellReuseIdentifier: "ItemTableViewCell")

答案 1 :(得分:1)

synchronized块与您希望waitnotify的同一对象一起使用。只需将synchronized关键字放在方法签名中即可锁定this(当前对象),但是当您在wait上调用notifybuffer时, synchronized上需要buffer个阻止。

您应该如下所示放入方法块,并从methid签名中删除synchronized关键字。

synchronized (buffer) {
    // call notify ,( prefer notifyAll.) on buffer
}

和类似的等待块。

以下是您可以尝试的更改

public class Producer implements Runnable {
    private Buffer buffer;
    private Callback callback;
    private String input;

    public Producer(Callback callback, Buffer buffer, String input) {
        this.callback = callback;
        this.buffer = buffer;
        this.input = input;
    }

    @Override
    public void run() {
        synchronized (buffer) {
            char[] array = input.toCharArray();
            try {
                for (int i = 0; i < array.length; i++) {
                    buffer.addChar(array[i]);   // production done, 
                    // 1. now notify the consumer thread and 
                    // 2. wait till consumer consumes and notifies.
                    System.out.println("Adding--------- data");
                    callback.returnData("Added " + array[i]);
                    buffer.notifyAll();         // 1. notify done [ consumer notified , this will make consumer get awake from wait state and try to re aquire the lock]
                    buffer.wait();          //2. waiting for notification from consumer thread.
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Consumer implements Runnable {

    private Callback callback;
    private Buffer buffer;

    public Consumer(Callback callback, Buffer buffer) {
        this.callback = callback;
        this.buffer = buffer;
    }

    @Override
    public void run() {
        try { // having try catch outside will enable you to call interrupt on
                // the Thread to stop it
            synchronized (buffer) {
                // though we check for interrupt flag but in case thread is
                // interrupted while waiting, and InterruptedException is
                // thrown, the flag will be cleared, hence we need to put try
                // catch block outside, other option is to put it inside and make thread true again from catch block.
                while (!Thread.currentThread().isInterrupted()) {
                    if (!buffer.isEmpty()) { 
                        System.out.println("Reading data");
                        callback.returnData(" Retrieved " + String.valueOf(buffer.readChar())); // consumption done, now
                                                                                                // 1. Notify the consumer thread
                                                                                                // 2. Wait till more production is done
                        buffer.notifyAll(); // 1. Consumer thread will get this notification and it will get in awakened state. It will try to aquire the lock on Buffer object.
                    } else {
                        System.out.println("Queue is empty ");
                        callback.returnData("Waiting");
                    }
                    buffer.wait();      // 2. wait until more production is done and producer notifies after production
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
相关问题