簡體   English   中英

一些線程卡在semaphore.aquire()(threads / semaphore / countdownlatch)

[英]Some threads gets stuck at semaphore.aquire() (threads/semaphore/countdownlatch)

我創建了一個小型電影租賃模擬程序。 以下是它的工作原理: - 主線程允許用戶輸入客戶名稱

  • 每個輸入的客戶都會啟動一個新線程(Customer Runnable)
  • 當創建了5個客戶時,租賃服務開始(等待5個倒計時)
  • 當客戶運行()時,他們將首先嘗試從信號量(具有5個可用許可證)獲取()許可證
  • 如果他們獲得許可,他們將等待1-10秒,然后租一輛車,然后等待1-3秒,然后開車
  • 當汽車被解除時,他們將全程開始循環迭代並嘗試獲得新的許可

所以這似乎工作得很好; 它適用於添加的前5個客戶。 在5號之后添加的客戶似乎在semaphore.aquire()等待等待,我無法理解為什么,所以我在這里問。 所有的幫助將非常贊賞:)

App.java:

import java.lang.System;import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class App {

    public static CountDownLatch latch = new CountDownLatch(5);
    public static Executor executor = Executors.newCachedThreadPool();
    public static Store store = new Store();
    public static Semaphore semaphore = new Semaphore(Store.getMovies().size());

    Scanner in;

    public App() {
        in = new Scanner(System.in);

        while (true) {
            executor.execute(new Customer(in.nextLine()));
        }
    }

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

    public CountDownLatch getLatch() {
        return latch;
    }

    public Executor getExecutor() {
        return executor;
    }

    public Semaphore getSemaphore() {
        return semaphore;
    }

}

Customer.java:

public class Customer implements Runnable {

    String name;

    public Customer(String name) {
        this.name = name;
    }

    public void run() {
        try {
            App.latch.countDown();
            App.latch.await();
        } catch (InterruptedException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }

        // Loop until ended
        while (true) {
            try {
                if (App.semaphore.availablePermits() == 0)
                    System.out.println("No available movies");

                // Acquire permit
                App.semaphore.acquire();

                // Sleep from 1-10 seconds before renting a Car
                int rand = 1 + (int) (java.lang.Math.random() * 10);
                Thread.sleep(rand * 1000);
                App.store.rent(this);

                // Sleep from 1-3 seconds before delivering the Car
                rand = 1 + (int) (Math.random() * 3);
                Thread.sleep(rand * 1000);
                App.store.deliver(this);

            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                App.semaphore.release();
            }
        }
    }

    public String getName() {
        return name;
    }
}

Store.java:

import java.lang.String;import java.lang.System;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class Store {

    private static List<Movie> movies;

    private static Lock lock = new ReentrantLock();

    public Store() {
        movies = new ArrayList<Movie>();
        movies.add(new Movie("Godfather"));
        movies.add(new Movie("LOTR"));
        movies.add(new Movie("Schindlers list"));
        movies.add(new Movie("Pulp fiction"));
        movies.add(new Movie("Fight club"));
    }

    public void rent(Customer c) {
        lock.lock();
        for (Movie movie : movies) {
            if (movie.getRentedBy() == null) {
                movie.setRentedBy(c);
                String str = c.getName() + " rented " + movie.getName();
                System.out.printf("%-30s", str);
                printStatus();
                break;
            }
        }
        lock.unlock();
    }

    // Deliver the Car
    public void deliver(Customer c) {
        lock.lock();
        for (Movie movie : movies) {
            if (movie.getRentedBy() != null && movie.getRentedBy().equals(c)) {
                movie.setRentedBy(null);
                String str = c.getName() + " delivered " + movie.getName();
                System.out.printf("%-30s", str);
                printStatus();
                break;
            }
        }
        lock.unlock();
    }

    public void printStatus() {
        String str;
        for (Movie m : movies) {
            System.out.print(m.getName() + " - ");
            if (m.getRentedBy() == null) {
                str = "available";
            } else {
                str = "rented by " + m.getRentedBy().getName();
            }
            System.out.printf("%-15s", str);
        }
        System.out.println();
    }

    public static List<Movie> getMovies() {
        return movies;
    }
}

Movie.java:

public class Movie {

    private String name;
    private Customer rentedBy;

    public Movie(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public Customer getRentedBy() {
        return rentedBy;
    }

    public void setRentedBy(Customer customer) {
        this.rentedBy = customer;
    }

}

嘗試在Semphore構造函數調用中添加true作為第二個參數。

默認情況下,沒有嘗試公平,您需要讓所有租房者輪流。 通常,剛剛返回電影的租用者將比等待信號量的人更快地acquire調用。 隨着增加的true論點“這個信號量將保證在競爭中首先授予許可” 信號量信號量

您的代碼的問題在於您的客戶線程運行無限循環並立即嘗試在發布后獲取信號量(另一種方法是客戶線程應該執行其業務並終止)。 第6個線程實際上正在等待轉彎但是獲得許可的可能性較小,因為前5個線程處於活動狀態。 要檢查這一點,您可以在釋放semaphore許可后將線程置於定時睡眠狀態。

此外,閂鎖正以錯誤的方式使用。 來電者應該致電await一旦等待所有5個線程調用countdown

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM