java - 如何同步两种方法以防止它们同时被不同的线程访问,但只允许一个方法的多个实例
问题描述
如何同步两种方法以防止它们同时被不同的线程访问,但只允许一个方法的多个实例?
例如,如果我创建了一个交通灯类和一个汽车类。我想要一个trafficlights.goleft();
和trafficlights.goright();
。
如何使汽车的许多线程可以同时运行 goleft 但右被锁定。
目前我已经在方法前面添加了同步关键字,但这完全锁定了它们。
public class Trafficlights{
public synchronized static void crossEast(int num) throws InterruptedException {
System.out.println("Car crossing Eastwards");
Thread.sleep(1000);
System.out.println("Car is now across");
}
public synchronized static void crossWest(int num) throws InterruptedException {
System.out.println("Car crossing westwards");
Thread.sleep(1000);
System.out.println("Car is now across");
}
public static void main(String[] args) {
for (int i =1; i < 20; i++) {
Car car = new Car(i);
car.run();
}
}
}
解决方案
我修改了我之前的答案,因为这不是一个很好的例子。
以前的解决方案应该是一个指南,因此您可以自己实现。这可能不是帮助你,而是让你感到困惑,所以我做了一个不同的例子来说明可以解决你的问题的东西。
请注意,我已经测试了这个解决方案并且它有效。
//Constants that represent left and right
private static final int LEFT = 1;
private static final int RIGHT = 2;
//permits set to 0 initially. No car is allowed to cross, either left or right
private static Semaphore goLeft = new Semaphore(0, true);
private static Semaphore goRight = new Semaphore(0, true);
//booleans to indicate whether cars will go left or right
public static boolean leftGreen = false, rightGreen = false;
public static void crossEast() throws InterruptedException {
goRight.acquire();
System.out.println("Car crossing Eastwards");
Thread.sleep(1000);
System.out.println("Car is now across");
goRight.release();
}
public static void crossWest() throws InterruptedException {
goLeft.acquire();
System.out.println("Car crossing westwards");
Thread.sleep(1000);
System.out.println("Car is now across");
goLeft.release();
}
//Method to be called by user, to turn a the right or left light to green
public static void turnOnLight(int light){
giveGreen(light);
try{
switchLight();
}
catch (InterruptedException ie){
ie.printStackTrace();
}
}
//Depending on the constant passed, leftGreen or rightGreen will be set to true
private static void giveGreen(int light){
if(light == LEFT){
leftGreen = true;
rightGreen = false;
}
else if(light == RIGHT){
leftGreen = false;
rightGreen = true;
}
else{
//you can throw a custom exception here
}
}
//This method will release a permit to the light that is green (true)
private static void switchLight() throws InterruptedException {
if(leftGreen){
if(goRight.availablePermits() > 0)
goRight.acquire();
goLeft.release();
//If thread tried to call goEast, it would be put to sleep
}
else if(rightGreen){
if(goLeft.availablePermits() > 0)
goLeft.acquire();
goRight.release();
//now allowed to go right
}
}
//Of course you shouldn't have throws and catch the exception at runtime instead
public static void main(String[] args) throws InterruptedException{
Thread[] cars = new Thread[4];
/*let's say we want to allow cars to only go left. If you don't
turn on any light, the cars won't move*/
turnOnLight(LEFT);
for(Car car : cars) {
car = new Thread(new Car());
System.out.print(car.getId()+": ");
car.run();
car.join();
}
}
我定义了一个简单的类Car
来演示它是如何工作的。这当然可以改变。
public class Car implements Runnable {
private boolean leftLight, rightLight;
public Car(){
this.leftLight = TrafficLights.leftGreen;
this.rightLight = TrafficLights.rightGreen;
}
@Override
public void run() {
try {
if(leftLight)
TrafficLights.crossWest();
else if(rightLight)
TrafficLights.crossEast();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
推荐阅读
- javascript - 单击包含特定 alt 标签的元素
- mongodb - MongoDb 身份验证在使用 docker 时访问数据库失败?
- while-loop - 在while循环中恐慌而不是在满足条件时停止
- node.js - AWS Lambda 函数:在查询 postgresql 时返回 null
- javascript - VueJS - 向多个组件发出事件(具有不同的父级)
- python - 如何在 QTextEdit 中进行计算时实时更新文本,而不会冻结界面?
- kubernetes - 在部署 Kubernetes 部署配置文件时为 AWS Fargate 设置 `platformVersion`
- inversion-of-control - 使用 Simple Injector 注册类型时的回调操作
- javascript - 倒数计时器自动触发提交按钮
- c# - 扩展方法中的访问依赖