Java两个线程之间的静态值共享

时间:2018-10-25 06:16:38

标签: java multithreading variables static runtime

我有两个不同的子进程,它们在两个不同的线程中运行两个不同的命令。第二个线程更新静态变量中的值,第一个线程获取并使用该值。

流程应如下所示:Thread2更新静态变量,thread1从静态变量中获取值,然后打印出来。 但是正在发生的流程是thread1首先从静态变量中获取值。在这种情况下,它的值为空,然后thread2更新该值。

两个线程都并行运行,我正在使用ExecutorService类来执行此操作。 我正在使用Runtime类运行命令,并使用while循环在两个线程上连续读取Stream的输出。

Thread1继续提供(X,Y)值,线程2仅在获取文本时才给出值。

我得到的输出:

(12,123)null-> thread2没有获得任何值,因此它不会更新,thread1将从静态变量中获得null
(123,334)null->线程1从静态变量中获取值并使用它,线程2然后将值“ Hello”更新为静态变量
(134,654)“ Hello”->线程1拾取并使用“ Hello”,然后thread2将值“ World”更新为静态变量

预期输出:

(12,123)null-> thread2没有获得任何值,因此它不会更新,thread1将从静态变量中获得null
(123,334)“ Hello”-> thread2将值“ Hello”更新为静态变量,thread1拾取并使用它
(134,654)“世界”->线程2将值“世界”更新为静态变量,线程1拾取并使用它

我也使用了volatile变量,但是输出没有变化。我在这里想念什么吗?请帮助...

2 个答案:

答案 0 :(得分:0)

您可以使用java.util.concurrent.Semaphore(从Java 5开始)来控制同时访问它们共有的变量的线程数。您可以使用线程数实例化此类(调用了acquire() )允许使用它们的共同点,如果您传递0,则意味着他们都不能修改它。

public class Threaad extends Thread{
volatile static String string;
public static void main(String[] args) {
    Semaphore semaphore = new Semaphore(0);
    Thread writer = new Write(semaphore);
    writer.setName("writer");
    Thread reader = new Read(semaphore);
    reader.setName("reader");
    ExecutorService service = Executors.newCachedThreadPool();
    service.execute(writer);
    service.execute(reader);
    service.shutdown();
}
}
class Write extends Thread{
    private Semaphore semaphore;
    Write(Semaphore semaphore){
        this.semaphore = semaphore;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            Threaad.string = String.valueOf(i);
            semaphore.release();
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class Read extends Thread{
    private Semaphore semaphore;
    Read(Semaphore semaphore){
        this.semaphore = semaphore;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                semaphore.acquire();
                System.out.println(Threaad.string);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

答案 1 :(得分:0)

使用线程时不要做的事情:在没有适当同步的情况下写入和读取相同的变量。您违反了此规则,因此遇到了不确定结果的预期问题。

想象一下以下执行流程:

T1: set var to "Hello"
T2: checks var and notices it is a String, proceeds to print it.
T1: set var to null
T2: prints var. (which is already null again)

一种可能的解决方案是T2首先将值复制到线程局部变量,然后继续对该变量进行处理,即:

while (running) {
  final String localString = staticString;
  if (localString != null) {
    System.out.println(localString);
  }
}

这样,您将创建变量当前值的“快照”,并实际上将输出当时已快照的内容。但是,这仍然不是在线程之间进行同步的有效方法,因为快照状态是完全随机的。想象发生以下情况:

T1: set var to "hello"
T1: set var to null
T2: checks var, it is null, do nothing.
T1: set var to "world"
T1: set var to null
T2: checks var, it is null, do nothing.

使用线程时,请记住,除非强制执行,否则任何时候任何线程的状态始终是不确定的。

有简单的方法可以强制执行特定状态,即synchronized的基本含义是“将所有内容搁置,以便我可以完成我的工作”,但是这效率低下,因为如果您不断搁置所有内容,则没有并行工作的意义。

从架构的角度来看,一种更好的方法来处理线程。通过使用触发器。在您的情况下,编写器线程可以具有仅包含相关信息(要输出的字符串)的queue,而生产者线程会将字符串放入该队列:

T2: checks queue, it is empty, do nothing.
T1: t1.put("Hello")
T2: checks queue, it contains "Hello", print that.
T2: checks queue, it is empty, do nothing.
T2: checks queue, it is empty, do nothing.
T1: t1.put("World")
T2: checks queue, it contains "World", print that.

我建议通读concurrent package,以了解Java提供的工具。使用这些,几乎所有问题都可以轻松解决。