为什么信号量不停止交易?

Why doesn't the semaphore stop thrading?

我使用信号量并且我希望当列表大小为零时线程等待其他线程但是为什么信号量不停止线程?信号量不是像通知和等待那样工作吗?

结果: 添加 去掉 添加 线程“Thread-2”java.lang.IndexOutOfBoundsException 中的异常:索引:0,大小:0

 ArrayList<String> list = new ArrayList<>();
            Semaphore semaphore = new Semaphore(0);
    
            new Producer(list, semaphore).start();
            new Producer(list, semaphore).start();
            new Customeer(list, semaphore).start();
            new Customeer(list, semaphore).start();
    //////////
        static class Customeer extends Thread {
    
            private List<String> list;
            private Semaphore semaphore;
    
            public Customeer(List<String> list, Semaphore semaphore) {
                this.list = list;
                this.semaphore = semaphore;
            }
    
            @Override
            public void run() {
    
    
                synchronized (list) {
                    if (list.size() == 0) {
                        try {
                            semaphore.acquire();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                        list.remove(0);
                        System.out.println("remove");
                }
            }
        }
    
        static class Producer extends Thread {
    
            private Semaphore semaphore;
            private List<String> list;
    
            public Producer(List<String> list, Semaphore semaphore) {
                this.list = list;
                this.semaphore = semaphore;
            }
    
            @Override
            public void run() {
    
                synchronized (list) {
    
                    list.add("hello");
                    semaphore.release();
                    System.out.println("add");
    
                }
    
            }
        }
    
    }

您似乎对信号量和同步感到困惑。当您希望允许 n 个线程一次访问同一资源时,使用信号量。 [n 可以为 1] 而同步则用于只允许 1 个线程访问资源。

使用信号量的解决方案

// Java implementation of a producer and consumer 
// that use semaphores to control synchronization. 

import java.util.concurrent.Semaphore; 

class Q { 
    // an item 
    int item; 

    // semCon initialized with 0 permits 
    // to ensure put() executes first 
    static Semaphore semCon = new Semaphore(0); 

    static Semaphore semProd = new Semaphore(1); 

    // to get an item from buffer 
    void get() 
    { 
        try { 
            // Before consumer can consume an item, 
            // it must acquire a permit from semCon 
            semCon.acquire(); 
        } 
        catch (InterruptedException e) { 
            System.out.println("InterruptedException caught"); 
        } 

        // consumer consuming an item 
        System.out.println("Consumer consumed item : " + item); 

        // After consumer consumes the item, 
        // it releases semProd to notify producer 
        semProd.release(); 
    } 

    // to put an item in buffer 
    void put(int item) 
    { 
        try { 
            // Before producer can produce an item, 
            // it must acquire a permit from semProd 
            semProd.acquire(); 
        } 
        catch (InterruptedException e) { 
            System.out.println("InterruptedException caught"); 
        } 

        // producer producing an item 
        this.item = item; 

        System.out.println("Producer produced item : " + item); 

        // After producer produces the item, 
        // it releases semCon to notify consumer 
        semCon.release(); 
    } 
} 

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

    public void run() 
    { 
        for (int i = 0; i < 5; i++) 
            // producer put items 
            q.put(i); 
    } 
} 

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

    public void run() 
    { 
        for (int i = 0; i < 5; i++) 
            // consumer get items 
            q.get(); 
    } 
} 

// Driver class 
class PC { 
    public static void main(String args[]) 
    { 
        // creating buffer queue 
        Q q = new Q(); 

        // starting consumer thread 
        new Consumer(q); 

        // starting producer thread 
        new Producer(q); 
    } 
} 

解决方案使用同步

// Java program to implement solution of producer 
// consumer problem. 

import java.util.LinkedList; 

public class Threadexample { 
    public static void main(String[] args) 
        throws InterruptedException 
    { 
        // Object of a class that has both produce() 
        // and consume() methods 
        final PC pc = new PC(); 

        // Create producer thread 
        Thread t1 = new Thread(new Runnable() { 
            @Override
            public void run() 
            { 
                try { 
                    pc.produce(); 
                } 
                catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } 
            } 
        }); 

        // Create consumer thread 
        Thread t2 = new Thread(new Runnable() { 
            @Override
            public void run() 
            { 
                try { 
                    pc.consume(); 
                } 
                catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } 
            } 
        }); 

        // Start both threads 
        t1.start(); 
        t2.start(); 

        // t1 finishes before t2 
        t1.join(); 
        t2.join(); 
    } 

    // This class has a list, producer (adds items to list 
    // and consumber (removes items). 
    public static class PC { 

        // Create a list shared by producer and consumer 
        // Size of list is 2. 
        LinkedList<Integer> list = new LinkedList<>(); 
        int capacity = 2; 

        // Function called by producer thread 
        public void produce() throws InterruptedException 
        { 
            int value = 0; 
            while (true) { 
                synchronized (this) 
                { 
                    // producer thread waits while list 
                    // is full 
                    while (list.size() == capacity) 
                        wait(); 

                    System.out.println("Producer produced-"
                                    + value); 

                    // to insert the jobs in the list 
                    list.add(value++); 

                    // notifies the consumer thread that 
                    // now it can start consuming 
                    notify(); 

                    // makes the working of program easier 
                    // to understand 
                    Thread.sleep(1000); 
                } 
            } 
        } 

        // Function called by consumer thread 
        public void consume() throws InterruptedException 
        { 
            while (true) { 
                synchronized (this) 
                { 
                    // consumer thread waits while list 
                    // is empty 
                    while (list.size() == 0) 
                        wait(); 

                    // to retrive the ifrst job in the list 
                    int val = list.removeFirst(); 

                    System.out.println("Consumer consumed-"
                                    + val); 

                    // Wake up producer thread 
                    notify(); 

                    // and sleep 
                    Thread.sleep(1000); 
                } 
            } 
        } 
    } 
} 

阅读资源以获得更清晰的内容

信号量:https://www.geeksforgeeks.org/producer-consumer-solution-using-semaphores-java/

同步:https://www.geeksforgeeks.org/producer-consumer-solution-using-threads-java/