某些线程卡在 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;
}
}
尝试添加 true
作为 Semphore 构造函数调用的第二个参数。
默认情况下,不尝试公平,您需要让所有租户轮流使用。通常,刚刚归还电影的承租人会比等待信号量的承租人更快地接到 acquire
电话。添加了 true
参数 "this semaphore will guarantee first-in first-out granting of permits under contention" Semaphore
您的代码的问题是您的客户线程运行无限循环并在释放后立即尝试获取信号量(另一种方法是客户线程应该执行其业务并终止)。第 6 个线程实际上正在等待轮到它,但由于前 5 个线程处于活动状态,因此获得许可的可能性较小。要检查这一点,您可以在释放 semaphore
许可后将线程置于定时睡眠状态。
另外,latch 的使用方式不对。调用者应该调用 await
一旦等待所有 5 个线程调用 countdown
我创建了一个小型电影租赁模拟程序。它是这样工作的: - 主线程让用户输入客户姓名
- 输入的每个客户都会启动一个新线程(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;
}
}
尝试添加 true
作为 Semphore 构造函数调用的第二个参数。
默认情况下,不尝试公平,您需要让所有租户轮流使用。通常,刚刚归还电影的承租人会比等待信号量的承租人更快地接到 acquire
电话。添加了 true
参数 "this semaphore will guarantee first-in first-out granting of permits under contention" Semaphore
您的代码的问题是您的客户线程运行无限循环并在释放后立即尝试获取信号量(另一种方法是客户线程应该执行其业务并终止)。第 6 个线程实际上正在等待轮到它,但由于前 5 个线程处于活动状态,因此获得许可的可能性较小。要检查这一点,您可以在释放 semaphore
许可后将线程置于定时睡眠状态。
另外,latch 的使用方式不对。调用者应该调用 await
一旦等待所有 5 个线程调用 countdown