该任务由三个吸烟者组成,分别是三个线程和一个名为Agent的类,Agent具有三个属性:烟草、打火机和纸张。
吸烟者只有其中一项,agent类应该将两项随机放在桌子上,然后吸烟者应该检查他们是否遗漏了这两项,然后捡起来,这样他们就可以用来吸烟了。
我有一个问题,我的产出有点奇怪,吸烟者倾向于同时挑选他们丢失的所有物品,尽管我认为我认为他们是不允许这样做的。
主班
public class Main {
public static void main(String[] args) {
Agent a = new Agent();
Pusac p1 = new Pusac(0,a,"Paper");
Pusac p2 = new Pusac(1,a,"Tobacco");
Pusac p3 = new Pusac(2,a,"Lighters");
p1.start();
p2.start();
p3.start();
}
} 我使用构造函数创建一个代理,并将其传递给smokers.Each烟雾器的构造函数,其中包含一个项、ID和代理。
烟民等级
public class Pusac extends Thread {
int id;
Agent a;
String owns;
public Pusac(int id, Agent a, String owns) {
this.id = id;
this.a = a;
this.owns = owns;
}
@Override
public void run() {
while(true) {
a.putTable();
if(this.owns.equals("Paper") && a.tobacco == true && a.lighters == true){
System.out.println("Smoker with ID " + this.id + " took tobacco and lighters.");
a.smoke();
} else if(this.owns.equals("Tobacco") && a.lighters == true && a.paper == true) {
System.out.println("Smoker with ID " + this.id + " took lighters and paper.");
a.smoke();
} else if(this.owns.equals("Lighters") && a.paper == true && a.tobacco == true) {
System.out.println("Smoker with ID " + this.id + " took paper and tobacco.");
a.smoke();
}
}
}
}在烟雾器类函数中,我检查该代理是否具有当前线程冒烟器所需的项,然后调用agent类中的函数。
代理类
public class Agent {
boolean paper;
boolean tobacco;
boolean lighters;
public void putTable() {
Random random = new Random();
int randomNumOne = random.nextInt(3);
switch(randomNumOne) {
case 0:
paper = true;
case 1:
tobacco = true;
case 2:
lighters = true;
}
int randomNumTwo = random.nextInt(3);
if(paper!=true && randomNumTwo==0) {
paper = true;
} else if(tobacco!=true && randomNumTwo == 1) {
tobacco = true;
} else if(lighters != true && randomNumTwo == 2) {
lighters = true;
}
}
public synchronized void smoke() {
System.out.println("Smoker with ID " + ((Pusac)Thread.currentThread()).id + " is smoking.");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(((Pusac)Thread.currentThread()).owns.equals("Paper")) {
this.tobacco = false;
this.lighters = false;
System.out.println("Smoker with ID " + ((Pusac)Thread.currentThread()).id + " put down tobacco and lighters.");
} else if(((Pusac)Thread.currentThread()).owns.equals("Tobacco")) {
this.paper =false;
this.lighters =false;
System.out.println("Smoker with ID " + ((Pusac)Thread.currentThread()).id + " put down paper and lighters.");
} else if (((Pusac)Thread.currentThread()).owns.equals("Lighters")) {
this.tobacco =false;
this.paper =false;
System.out.println("Smoker with ID " + ((Pusac)Thread.currentThread()).id + " put down paper and tobacco.");
}
}
}最后一个名为代理的类由一个函数组成,该函数将两个项随机放置在表中,项是布尔,然后我有函数烟雾,它只检查哪个吸烟者正在吸烟,然后将所有内容设置为false。
我得到的输出
Smoker with ID 2 took paper and tobacco.
Smoker with ID 1 took lighters and paper.
Smoker with ID 0 took tobacco and lighters.
Smoker with ID 2 is smoking.
Smoker with ID 2 put down paper and tobacco.
Smoker with ID 2 took paper and tobacco.
Smoker with ID 0 is smoking.
Smoker with ID 0 put down tobacco and lighters.
Smoker with ID 0 took tobacco and lighters.
Smoker with ID 1 is smoking.这是错误的,因为在现实中,只有一个人应该一次挑选一些东西,然后吸烟,以便其他人也可以拥有它。
衷心感谢您的帮助。
发布于 2021-12-05 14:51:35
,这是错误的,因为在现实中,只有一个人应该一次挑选一些东西,然后吸烟,这样其他人也可以拥有它。
因为您的Pusac线程类run方法不受任何人保护,所以您需要使用用于锁定smoke方法的相同监视器来使用run代码块。您可以通过synchronizing来尝试smoke和run方法。
public void smoke() {
synchronized(Agent.class) {
......
}
}
@Override
public void run() {
while(true) {
synchronized(Agent.class) {
......
}
}
}发布于 2021-12-05 14:58:05
在线程之间共享可变变量时,必须以不同的方式处理这些变量,否则每个读取线程可能会看到不同的值。
tldr:
修复现有程序的最简单方法很可能是定义所有“易失性”变量,如
volatile boolean paper;
volatile boolean tobacco;
volatile boolean lighters;更长的解释是:出于性能原因,线程可能不会通过(缓慢) RAM访问来读取变量,而是从缓存中获取它们。只要相同的线程读取和写入变量,但当您试图在一个线程中设置值并从另一个线程读取它时,此操作就会失败。读取线程可能仍然会看到旧的值。
修复该问题的一种方法是声明变量易失性。这基本上指示要始终从RAM中读取值--对于这样大小的项目来说,这不应该有太大的区别。
您也可以使用java.util.concurrent.atomic.AtomicBoolean,而不是原始布尔值,这对于这个用例来说应该是一样的。
解决此问题的另一种方法是确保变量上的所有写更改都在同步块内。这样,开销就在写过程上,而不再在读者身上了。
然而,随着线程安全成为一个快速深入的话题,如果您计划做更多这样的多线程应用程序,就有一些关于这个主题的广泛阅读材料;-)
https://stackoverflow.com/questions/70235350
复制相似问题