java - 如何在另一个线程 JAVA 中访问 volatile 变量
问题描述
我正在尝试从多个正在运行的线程访问变量。
我有一个启动 2 个线程的主类,一个生产者和一个消费者。
生产者线程读取一个二进制文件。对于该二进制文件中的每一行,生产者线程从中创建一个对象,并通过阻塞队列将该对象传递给消费者线程。
然后,CONSUMER 将通过阻塞队列传入的对象,并将该对象中字段的值输出到文本文件。
有时生产者线程正在读取的二进制文件中存在错误。
当二进制文件中有太多错误时,我希望消费者线程将其输出的 txt 文件的扩展名更改为 .err
我的问题:我不知道如何在消费者线程中修改生产者线程的值。我一直在阅读我可以使用 volatile 字段。但我不知道在线程之间使用它的正确方法是什么。
这是我的代码的一个非常简短且不太复杂的示例:
public class Main
{
private volatile static boolean tooManyErrors= false;
public static void main(String[] args)
{
BlockingQueue<binaryObject> queue = new LinkedBlockingQueue<>(null);
binaryObject poison = null;
new Thread(new Producer(tooManyErrors, queue, poison)).start();
new Thread(new Consumer(tooManyErrors, queue, poison)).start();
}
}
public class Producer implements Runnable
{
private final BlockingQueue<binaryObject> queue;
private final binaryObject POISON;
private boolean tooManyErrors;
private int errorsCounter = 0;
public Producer(boolean tooManyErrors, BlockingQueue<binaryObject> queue,
binaryObject POISON)
{
this.tooManyErrors = tooManyErrors;
this.queue = queue;
this.POISON = POISON;
}
@Override
public void run()
{
try
{
process();
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
finally
{
while (true)
{
try
{
queue.put(POISON);
break;
}
catch (InterruptedException e)
{
//...
}
}
}
}
private void process() throws InterruptedException
{
//here is where all the logic to read the file and create
//the object goes in. counts the number of errors in the file
//if too many errors, want to change the tooManyErrors to true
if(errorsCounter > 100)
{
tooManyErrors = true;
}
}
}
public class Consumer implements Runnable
{
private final BlockingQueue<binaryObject> queue;
private final binaryObject POISON;
private boolean tooManyErrors;
//variable with extension name
private String extension;
public Consumer(boolean tooManyErrors, BlockingQueue<Integer> queue,
binaryObject POISON)
{
this.tooManyErrors = tooManyErrors;
this.queue = queue;
this.POISON = POISON;
}
@Override
public void run()
{
try
{
while (true)
{
binaryObject take = queue.take();
process(take);
// if this is a poison pill, break, exit
if (take == POISON)
{
break;
}
}
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
}
private void process(Integer take) throws InterruptedException
{
//this is where all the logic goes that takes the binaryObject
//grabs all the fields from it such as binaryObject.getFileName,
//happens. It then outputs a text file with all the fields grabbed
//from the object. If the producer thread found too many errors
// I want the extension changed to .err instead of .txt
// I dont know how to do that
if(tooManyErrors == false)
{
extension = ".txt";
createFile(extension);
}
else
{
extension = ".err";
createFile(extension);
}
}
private void createFile(String extension)
{
//...
}
}
解决方案
好的,这里有几件事。我假设只有一个生产者和一个消费者。如果是这种情况,您可以将类生产者和消费者标记为static
. 如果您将类标记为static
,则将仅存在其字段的一个实例——它将是一个单例。您可以将生产者和消费者的任何字段标记为非私有,并且只需访问这些字段。 somethingINeed = Producer.fieldThatIsNotPrivate
从消费者内部,反之亦然。
另一种选择是保留您想要的对象的句柄并将其传递给构造函数。
Producer p = new Producer(tooManyErrors, queue, poison);
Consumer c = new Consumer(tooManyErrors, queue, poison);
p.setConsumer(c);
c.setProducer(p);
new Thread(p).start();
new Thread(c).start();
您可以为需要共享信息的任何字段创建访问器。
推荐阅读
- css - 动画 SVG 箭头和 z-index
- github-cli - 如何在通过 Git-CLI 创建 repo 时将 gitignore 文件和许可证设置为 None 并将 add "origin" git remote 设置为 Yes all?
- sql - 如何统计同一天发生的客户行为发生次数?
- python - 我在 django 中收到 No reverse match 错误,但它使用 urls.py
- java - Android(Java)是否有任何类似于 PHP 的 file_get_contents($url) 的功能?
- flutter - 如何使用 FLUTTER-FFMPEG 对图像和视频应用过滤器
- python - 返回字典中具有最高值的键
- javascript - 将图像作为 9B 文件上传到 Firestore
- python - 使用 Beautiful Soup 进行网页抓取:不显示整个表格?
- c# - 为什么 C# 公共静态变量不需要实例化?