简体   繁体   English

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

[英]static Value Sharing between two Threads Java

I have two different subprocess running two different commands in two different threads.the second thread updates a value in a static variable and the first thread takes the value and uses it. 我有两个不同的子进程在两个不同的线程中运行两个不同的命令。第二个线程更新静态变量中的值,第一个线程获取并使用该值。

The flow should be like this : Thread2 updates static variable and thread1 takes up the value from the static variable and then prints it.. but the flow that's happening is thread1 picks up the value from the static variable first. 流程应该是这样的:Thread2更新静态变量,并且thread1从静态变量中获取值,然后将其打印..但是发生的流程是thread1首先从静态变量中获取了值。 In this case it has a null value and then thread2 updates the value. 在这种情况下,它具有空值,然后thread2更新该值。

Both the threads are running in parallel, i am using ExecutorService class to do this. 两个线程并行运行,我正在使用ExecutorService类来执行此操作。 I'm using Runtime class to run the command and a while loop to read the outputs from the Stream continiously on both threads. 我正在使用Runtime类运行命令,并使用while循环在两个线程上连续读取Stream的输出。

Thread1 keeps on giving (X,Y) values , Thread two gives out the value only when it gets a text. Thread1继续提供(X,Y)值,线程2仅在获取文本时才给出值。

Output I'm getting : 我得到的输出:

(12, 123) null --> thread2 didn't get any value so it doesnt update, thread1 would get null from the static variable (12,123)null-> thread2没有获得任何值,因此它不会更新,thread1将从静态变量获得null
(123,334) null --> thread1 picks up the value from the static variable and uses it, thread2 then updates value "Hello" to static variable (123,334)null->线程1从静态变量中获取值并使用它,线程2然后将值“ Hello”更新为静态变量
(134,654) "Hello" --> thread1 picks up "Hello" and uses it, thread2 then updates value "World" to static variable (134,654)“ Hello”-> thread1拾取并使用“ Hello”,然后thread2将值“ World”更新为静态变量

Expected output: 预期产量:

(12, 123) null --> thread2 didn't get any value so it doesnt update, thread1 would get null from the static variable (12,123)null-> thread2没有获得任何值,因此它不会更新,thread1将从静态变量获得null
(123,334) "Hello" --> thread2 updates value "Hello" to static variable, thread1 picks it up and uses it (123,334)“ Hello”-> thread2将值“ Hello”更新为静态变量,thread1拾取并使用它
(134,654) "World" --> thread2 updates value "World" to static variable, thread1 picks it up and uses it (134,654)“世界”->线程2将值“世界”更新为静态变量,线程1拾取并使用它

i've used a volatile variable too but the output didn'y change. 我也使用了volatile变量,但是输出没有改变。 I'm i missing something here? 我在这里想念什么吗? Please help... 请帮忙...

You can use java.util.concurrent.Semaphore(as of Java 5) to control the number of threads simultaneously accessing a variable they have in common.You instantiate this class with the number of threads(which have called acquire()) allowed to use what they have in common and if you pass 0, it means none of them can modify it. 您可以使用java.util.concurrent.Semaphore(从Java 5开始)来控制同时访问它们共有的变量的线程数。您可以使用允许执行以下操作的线程数来实例化此类。使用它们的共同点,如果您传递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();
            }
        }
    }
}

Things not to do when using threads: writing and reading the same variable without proper synchronization. 使用线程时不要做的事情:在没有正确同步的情况下写入和读取相同的变量。 You violate this rule and therefore you run into the expected problems of undefined results. 您违反了此规则,因此遇到了不确定结果的预期问题。

Imagine the following execution flow: 想象以下执行流程:

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)

A possible solution is that T2 first copies the value to a thread-local variable and then proceeds working on that one, iE: 可能的解决方案是T2首先将值复制到线程局部变量,然后继续对该变量进行操作,即:

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

This way you create a "snapshot" of the current value of the variable, and will actually output what has been snapshotted at that moment. 这样,您就可以创建变量当前值的“快照”,并且实际上将输出当时已快照的内容。 However this still is no valid way to synchronize between threads, because the snapshot state is completely random. 但是,这仍然不是在线程之间进行同步的有效方法,因为快照状态是完全随机的。 Imagine that the following happens: 想象发生以下情况:

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.

When working with Threads you need to keep in mind that the state of any thread at any time is always undefined, unless you enforce it. 使用线程时,请记住,除非强制执行,否则任何时候任何线程的状态始终是不确定的。

There are simple ways to enforce a specific state iE synchronized which basically means "Put the whole thing on hold so I can do my work", however that is quiet inefficient, as there is no point of working in parallel if you constantly put everything on hold. 有几种简单的方法可以强制实现特定状态的synchronized ,这基本上意味着“将整个事情搁置,以便我可以做我的工作”,但是这效率很低,因为如果不断地将所有内容放在上面,则没有并行工作的意义。保持。

A much better way to approach Threading is from an architectural point of view iE by using triggers. 从架构的角度来看,使用触发器是一种更好的处理线程的方法。 In your case the writer-thread could have a queue with only relevant information (the strings to output), and the producer-thread will put strings into that 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.

I recommend to read through the concurrent package to learn about the tools Java offers. 我建议通读并发包以了解Java提供的工具。 Almost all problems can be easily solved using those. 使用这些几乎可以解决所有问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM