gpt4 book ai didi

Java 线程程序无法使用 wait() 和 notifyAll()

转载 作者:搜寻专家 更新时间:2023-11-01 03:20:18 25 4
gpt4 key购买 nike

下面是我的程序。总是线程 0 获取打印机,其他线程不获取它。有一个打印机对象,我希望多个作业线程使用打印机。如何使这个程序工作,以便所有作业都得到打印机。对我来说,代码流似乎没问题。正在同步单个打印机对象。请帮忙。

    package classesTesting;

public class PrinterQueue {

final static Printer printer = new Printer();;

public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("In Main");

for (int i = 0; i < 5; i++) {
new Thread(new Jobs(), "Thread - " + i).start();
System.out.println("started " + i + " thread");
}

}

}

class Printer {
private boolean isUsed;

Printer() {
this.isUsed = false;
}

public void setUsed(boolean used) {
this.isUsed = used;
}

public boolean isUsed() {

return this.isUsed;
}
}

class Jobs implements Runnable {

String name;
boolean isDataAvailble;

Jobs() {
this.isDataAvailble = true;
}

public void setNoData(boolean noData) {
this.isDataAvailble = false;
}

@Override
public void run() {

while (isDataAvailble) {

if (PrinterQueue.printer.isUsed()) {
try {
System.out.println(Thread.currentThread()
+ "WAITING FOR PRINTER");
synchronized (PrinterQueue.printer) {
PrinterQueue.printer.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}

} else {
synchronized (PrinterQueue.printer) {
System.out.println(Thread.currentThread() + "GOT PRINTER");
PrinterQueue.printer.setUsed(true);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
PrinterQueue.printer.setUsed(false);
PrinterQueue.printer.notify();
}
}
}

try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}

您好,我修改了我的程序,先获取锁再检查条件。即使这样,线程 0 也总是得到打印机。其他线程饿死。

修改后的程序:

    package classesTesting;

public class PrinterQueue {

static Printer printer;

public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("In Main");

printer = new Printer();

for (int i = 0; i < 5; i++) {
Jobs j1 = new Jobs();
j1.setPrinter(printer);

Thread t1 = new Thread(j1, "Thread - " + i);
t1.start();

System.out.println("started " + i + " thread");
}

}

}

class Printer {
private boolean isUsed;

Printer() {
this.isUsed = false;
}

public void setUsed(boolean used) {
this.isUsed = used;
}

public boolean isUsed() {

return this.isUsed;
}
}

class Jobs implements Runnable {

String name;
Printer printer;

public Printer getPrinter() {
return printer;
}

public void setPrinter(Printer printer) {
this.printer = printer;
}

boolean isDataAvailble;

Jobs() {
this.isDataAvailble = true;
}

public void setNoData(boolean noData) {
this.isDataAvailble = false;
}

@Override
public void run() {

while (isDataAvailble) {
synchronized (PrinterQueue.printer) {
if (this.printer.isUsed()) {
try {
System.out.println(Thread.currentThread()
+ "WAITING FOR PRINTER");

PrinterQueue.printer.wait();

} catch (InterruptedException e) {
e.printStackTrace();
}
}

else {

System.out.println(Thread.currentThread() + "GOT PRINTER");

PrinterQueue.printer.setUsed(true);

try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}

PrinterQueue.printer.setUsed(false);
PrinterQueue.printer.notify();
}
}
}

}

}

最佳答案

如果您希望资源以公平的方式供所有线程使用,最好使用带有fair = true 参数的ReentrantLock。也永远不要依赖以并发方式更改的非 volatile 变量。这是固定代码:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class PrinterQueue {
static Printer printer;

public static void main(String[] args) {
System.out.println("In Main");
printer = new Printer();
for (int i = 0; i < 5; i++) {
// I added printer constructor parameter to pass the same printer
// to all the Jobs
new Thread(new Jobs(printer), "Thread - " + i).start();
System.out.println("started " + i + " thread");
}
}
}

class Printer {
// internally printer holds a fair ReentrantLock
Lock lock = new ReentrantLock(true);

// call this to get the printer
public void acquire() {
lock.lock();
}

// call this to release the printer, so it's available for other threads
public void release() {
lock.unlock();
}
}

class Jobs implements Runnable {
// Declare isDataAvailble as volatile as you're going to change it from another thread
volatile boolean isDataAvailble;
private final Printer printer;

// constructor now takes the printer argument
Jobs(Printer printer) {
this.isDataAvailble = true;
this.printer = printer;
}

@Override
public void run() {
try {
while (isDataAvailble) {
System.out.println(Thread.currentThread()
+ "Trying to get the printer");
// get the printer
this.printer.acquire();
try {
System.out.println(Thread.currentThread()
+ "Printer acquired!");
// use it
Thread.sleep(3000);
} finally {
// Release the printer. Better to do it in finally block
// so you will release it even if some unexpected exception occurs
this.printer.release();
}
}

Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

关于Java 线程程序无法使用 wait() 和 notifyAll(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32305150/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com