首页 > 解决方案 > 如何在另一个线程 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)
   {
     //...
   }

}

标签: javamultithreading

解决方案


好的,这里有几件事。我假设只有一个生产者和一个消费者。如果是这种情况,您可以将类生产者和消费者标记为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();

您可以为需要共享信息的任何字段创建访问器。


推荐阅读