如何防止 java 中的线程饥饿
How to prevent thread starvation in java
我已经编写了解决以下问题的程序,但我正试图让它免于挨饿,但我不确定如何实现它。所以,北方农民和南方农民过桥的机会是一样的。
场景
一座单车道桥连接北滕布里奇和南滕布里奇这两个佛蒙特州村庄。两个村庄的农民使用这座桥将他们的农产品运送到邻近的城镇。如果北行和南行的农民同时上桥,桥可能会死锁(佛蒙特州的农民很顽固,无法后退。)
这是我尝试过的:
package threading.practice;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SingleLaneBridge {
public static void main(String[] args)
{
final Bridge bridge = new Bridge();
Thread thNorthbound = new Thread( new Runnable() {
@Override
public void run() {
while(true)
{
Farmer farmer = new Farmer(bridge);
Thread th = new Thread(farmer);
farmer.setName("North Farmer : "+th.getId());
th.start();
try
{
TimeUnit.SECONDS.sleep((long)(Math.random()*10));
}
catch(InterruptedException iex)
{
iex.printStackTrace();
}
}
}
});
Thread thSouthbound = new Thread( new Runnable() {
@Override
public void run() {
while(true)
{
Farmer farmer = new Farmer(bridge);
Thread th = new Thread(farmer);
farmer.setName("South Farmer : "+th.getId());
th.start();
try
{
TimeUnit.SECONDS.sleep((long)(Math.random()*10));
}
catch(InterruptedException iex)
{
iex.printStackTrace();
}
}
}
});
thNorthbound.start();
thSouthbound.start();
}
}
class Bridge
{
private final Semaphore semaphore;
public Bridge()
{
semaphore = new Semaphore(1);
}
public void crossBridge(Farmer farmer)
{
try
{
System.out.printf("Farmer %s is trying to cross the bridge.\n",farmer.getName());
semaphore.acquire();
System.out.printf("Farmer %s is crossing the bridge.\n",farmer.getName());
long duration = (long)(Math.random() * 10);
TimeUnit.SECONDS.sleep(duration);
}
catch(InterruptedException iex)
{
iex.printStackTrace();
}
finally
{
System.out.printf("Farmer %s has crossed the bridge.\n",farmer.getName());
semaphore.release();
}
}
}
class Farmer implements Runnable
{
private String name;
private Bridge bridge;
public Farmer(Bridge bridge)
{
this.bridge = bridge;
}
public void run()
{
bridge.crossBridge(this);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
java.util.concurrent.Semaphore
有一个 constructor that takes a fairness flag。设置后,它会排队获取并保证它们按 fifo 顺序执行。
文档对标志的使用有说明:
Generally, semaphores used to control resource access should be initialized as fair, to ensure that no thread is starved out from accessing a resource. When using semaphores for other kinds of synchronization control, the throughput advantages of non-fair ordering often outweigh fairness considerations.
我已经编写了解决以下问题的程序,但我正试图让它免于挨饿,但我不确定如何实现它。所以,北方农民和南方农民过桥的机会是一样的。
场景 一座单车道桥连接北滕布里奇和南滕布里奇这两个佛蒙特州村庄。两个村庄的农民使用这座桥将他们的农产品运送到邻近的城镇。如果北行和南行的农民同时上桥,桥可能会死锁(佛蒙特州的农民很顽固,无法后退。)
这是我尝试过的:
package threading.practice;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SingleLaneBridge {
public static void main(String[] args)
{
final Bridge bridge = new Bridge();
Thread thNorthbound = new Thread( new Runnable() {
@Override
public void run() {
while(true)
{
Farmer farmer = new Farmer(bridge);
Thread th = new Thread(farmer);
farmer.setName("North Farmer : "+th.getId());
th.start();
try
{
TimeUnit.SECONDS.sleep((long)(Math.random()*10));
}
catch(InterruptedException iex)
{
iex.printStackTrace();
}
}
}
});
Thread thSouthbound = new Thread( new Runnable() {
@Override
public void run() {
while(true)
{
Farmer farmer = new Farmer(bridge);
Thread th = new Thread(farmer);
farmer.setName("South Farmer : "+th.getId());
th.start();
try
{
TimeUnit.SECONDS.sleep((long)(Math.random()*10));
}
catch(InterruptedException iex)
{
iex.printStackTrace();
}
}
}
});
thNorthbound.start();
thSouthbound.start();
}
}
class Bridge
{
private final Semaphore semaphore;
public Bridge()
{
semaphore = new Semaphore(1);
}
public void crossBridge(Farmer farmer)
{
try
{
System.out.printf("Farmer %s is trying to cross the bridge.\n",farmer.getName());
semaphore.acquire();
System.out.printf("Farmer %s is crossing the bridge.\n",farmer.getName());
long duration = (long)(Math.random() * 10);
TimeUnit.SECONDS.sleep(duration);
}
catch(InterruptedException iex)
{
iex.printStackTrace();
}
finally
{
System.out.printf("Farmer %s has crossed the bridge.\n",farmer.getName());
semaphore.release();
}
}
}
class Farmer implements Runnable
{
private String name;
private Bridge bridge;
public Farmer(Bridge bridge)
{
this.bridge = bridge;
}
public void run()
{
bridge.crossBridge(this);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
java.util.concurrent.Semaphore
有一个 constructor that takes a fairness flag。设置后,它会排队获取并保证它们按 fifo 顺序执行。
文档对标志的使用有说明:
Generally, semaphores used to control resource access should be initialized as fair, to ensure that no thread is starved out from accessing a resource. When using semaphores for other kinds of synchronization control, the throughput advantages of non-fair ordering often outweigh fairness considerations.