简体   繁体   English

多线程同步在Java中不起作用

[英]Multithreading Synchronization not working in Java

I am trying an example of multi threading in java. 我正在尝试Java中的多线程示例。 There was an example on multithreading Synchronization in Java Complete reference 7th Edition. Java Complete参考书第7版中有一个有关多线程同步的示例。 The example works fine. 该示例工作正常。 but when i slightly add a line to create another thread of the same class this does not work. 但是,当我稍微添加一行以创建同一类的另一个线程时,此操作将无效。 Could some please let me know why this is happening. 请让我知道为什么会这样。 The example is given below. 下面给出示例。 The below code is a classic exacple of producer and consumer. 下面的代码是生产者和消费者的经典例子。 Where there is a single producer it works fine when i have 2 producers then it will fail. 如果只有一个生产者,则当我有2个生产者时,它可以正常工作,然后它将失败。 It just puts till 15 and stops. 直到15点才停止。

class Q {

    int n;
    boolean valueSet = false;

    synchronized int get() {
        while (!valueSet) {
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        }
        System.out.println("Got: " + n);
        valueSet = false;
        notify();
        return n;
    }

    synchronized void put(int n) {
        while (valueSet) {
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        }
        this.n = n;
        valueSet = true;
        System.out.println("Put: " + n);
        notify();
    }
}

class Producer implements Runnable {

    Q q;

    Producer(Q q) {
        this.q = q;
        new Thread(this, "Producer").start();
        //new Thread(this, "Producer2").start();
    }

    public void run() {
        int i = 0;
        while (true) {
            q.put(i++);
        }
    }
}

class Consumer implements Runnable {

    Q q;

    Consumer(Q q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }

    @Override
    public void run() {
        while (true) {
            q.get();
        }
    }
}

public class PCFixed {

    public static void main(String[] args) {
        Q q = new Q();
        Producer P1 = new Producer(q);
        new Consumer(q);
        Producer P2 = new Producer(q);
        System.out.println("Press Control-C to stop.");
    }
}

Q is written to only accept one value at a time. Q被写入为一次仅接受一个值。 You need to change put to be a boolean method - it returns true if valueset is true and then proceeds as normal, and returns false if valueset is false and returns without doing anything. 您需要将put更改为布尔方法-如果valueset为true,则返回true,然后按常规进行;如果valueset为false,则返回false,并且不执行任何操作。 Then the methods calling put will need to keep retrying until they get a true response. 然后,调用put的方法将需要继续重试,直到获得真正的响应为止。 This way multiple consumers can use the same Q object without interfering with each other. 这样,多个使用者可以使用相同的Q对象,而不会互相干扰。

A better solution if you're using multiple producers is to use a ConcurrentLinkedQueue , which is a thread-safe queue. 如果使用多个生产者,更好的解决方案是使用ConcurrentLinkedQueue ,它是线程安全的队列。 The producers will offer integers to the queue, and the consumers will poll the queue for integers. 该生产商将offer整数队列,而消费者将poll的整数队列。 Multiple producers can simultaneously offer integers without interfering with each other, and multiple consumers can simultaneously poll integers without interfering with each other. 多个生产者可以同时offer整数而不会互相干扰,多个使用者可以同时poll整数而不会互相干扰。

The example of concurrency you provide uses a single boolean flag to check whether there is a signal or not. 您提供的并发示例使用单个boolean标志来检查是否有信号。

So this is more of a Semaphore arrangement than a producer consumer arrangement. 因此,这更多是Semaphore安排,而不是生产者消费者安排。 It is too simplistic to deal with an arbitrary number of Thread s. 处理任意数量的Thread太简单了。

If you really want to use producer consumer you are going to need a queue that holds more than one item. 如果您真的想使用生产者使用者,则需要一个队列,其中包含多个项目。

static final AtomicBoolean run = new AtomicBoolean(true);

static class Producer implements Runnable {

    final BlockingQueue<String> blockingQueue;

    public Producer(BlockingQueue<String> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        while (run.get()) {
            blockingQueue.add("Value from " + Thread.currentThread().getName());
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
                //doesn't matter.
            }
        }
    }
}

static class Consumer implements Runnable {

    final BlockingQueue<String> blockingQueue;

    public Consumer(BlockingQueue<String> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        while (run.get()) {
            final String item;
            try {
                item = blockingQueue.take();
            } catch (InterruptedException ex) {
                return;
            }
            System.out.println(item);
        }
    }
}

public static void main(String[] args) throws InterruptedException {
    final LinkedBlockingQueue<String> lbq = new LinkedBlockingQueue<>();
    final ExecutorService executorService = Executors.newCachedThreadPool();
    executorService.submit(new Consumer(lbq));
    for (int i = 0; i < 10; ++i) {
        executorService.submit(new Producer(lbq));
    }
    Thread.sleep(10000);
    run.set(false);
    executorService.shutdownNow();
}

This simple example uses a LinkedBlockingQueue to post events to and read events from. 这个简单的示例使用LinkedBlockingQueue将事件发布到事件或从中读取事件。

The Producer puts String s into the queue with it's own Thread name (they do this every 100ms). Producer使用自己的Thread名称(每个100毫秒执行一次)将String放入队列。 The Consumer takes from the queue and prints the String . Consumer从队列中取出并打印String

The queue is a BlockingQueue so the take method will block if the queue is empty. 该队列是一个BlockingQueue因此如果队列为空,则take方法将阻塞。

You can easily change the number of Producer s and Consumer s by changing the loops that add items to the ExecutorService . 通过更改将项目添加到ExecutorService的循环,可以轻松更改ProducerConsumer的数量。 Experiment, see how it works. 做实验,看看它是如何工作的。

The AtomicBoolean flag allows the program to shutdown all the child processes spawned. AtomicBoolean标志允许程序关闭所有产生的子进程。

notifyAll替换每次出现的notify

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM