我有两个不同的子进程,它们在两个不同的线程中运行两个不同的命令。第二个线程更新静态变量中的值,第一个线程获取并使用该值。
流程应如下所示: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变量,但是输出没有变化。我在这里想念什么吗?请帮助...
答案 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提供的工具。使用这些,几乎所有问题都可以轻松解决。