Почему семафор не перестает работать?

#java #multithreading #semaphore

Вопрос:

Я использую семафор, и я хочу, чтобы, когда размер списка равен нулю, поток ждал другого потока, Но почему семафор не прекращает работу? Разве семафор не работает как уведомление и ожидание?

результат: добавить удалить добавить исключение в потоке «Поток-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");
    
                }
    
            }
        }
    
    }
 

Ответ №1:

вы, кажется, путаете семафоры и синхронизацию. семафоры используются, когда вы хотите разрешить 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/