2

我创建了一个小型电影租赁模拟程序。它是这样工作的: - 主线程让用户输入客户姓名

  • 每个输入的客户都会启动一个新线程(Customer Runnable)
  • 创建 5 个客户后,开始租赁服务(等待 5 个倒计时)
  • 当客户运行()时,他们将首先尝试从信号量中获取()一个许可(有 5 个可用许可)
  • 如果他们获得许可证,他们将等待 1-10 秒,然后租车,然后等待 1-3 秒,然后交付汽车
  • 当汽车交付时,他们将重新开始循环迭代并尝试获得新的许可证

所以这似乎工作得很好;它适用于添加的前 5 个客户。5 号之后添加的客户似乎在 semaphore.aquire() 处等待,我不明白为什么,所以我在这里问。非常感谢所有帮助:)

应用程序.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;
    }

}

客户.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;
    }
}

存储.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;
    }
}

电影.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;
    }

}
4

2 回答 2

6

尝试添加true作为 Semphore 构造函数调用的第二个参数。

默认情况下,不会尝试公平,您需要让所有租户轮流进行。通常,刚归还电影的租用者会acquire比等待信号量的租用者更快地接听电话。添加了true参数“此信号量将保证争用许可的先进先出授予”信号量

于 2015-05-27T23:24:55.293 回答
2

您的代码的问题是您的客户线程运行无限循环并在发布后立即尝试获取信号量(另一种方法是客户线程应该执行其业务并终止)。第 6 个线程实际上正在等待轮到它,但由于前 5 个线程处于活动状态,因此获得许可的可能性较小。semaphore要检查这一点,您可以在释放许可后将线程置于定时睡眠状态。

此外,闩锁的使用方式错误。调用者应该调用await一次,等待所有 5 个线程调用countdown

于 2015-05-27T23:48:58.477 回答