相关疑难解决方法(0)

线程之间是否共享静态变量?

我的老师在一个关于线程的上层Java课上说了一些我不确定的东西.

他表示以下代码不一定会更新ready变量.根据他的说法,两个线程不一定共享静态变量,特别是在每个线程(主线程对ReaderThread)在其自己的处理器上运行并因此不共享相同的寄存器/缓存/等和一个CPU的情况下不会更新另一个.

从本质上讲,他说有可能ready在主线程中更新,但不在主线程中更新ReaderThread,因此ReaderThread将无限循环.

他还声称该程序可以打印042.我知道如何42打印,但不是0.他提到当number变量设置为默认值时会出现这种情况.

我想也许并不能保证在线程之间更新静态变量,但这对我来说非常奇怪.制作readyvolatile会纠正这个问题吗?

他展示了这段代码:

public class NoVisibility {  
    private static boolean ready;  
    private static int number;  
    private static class ReaderThread extends Thread {   
        public void run() {  
            while (!ready)   Thread.yield();  
            System.out.println(number);  
        }  
    }  
    public static void main(String[] args) {  
        new ReaderThread().start();  
        number = 42;  
        ready = true;  
    }  
}
Run Code Online (Sandbox Code Playgroud)

java concurrency static multithreading memory-visibility

92
推荐指数
5
解决办法
8万
查看次数

Java内存模型:volatile变量和之前发生的

我想澄清一下,在关系与volatile变量一起工作之前会发生什么.我们有以下变量:

public static int i, iDst, vDst;
public static volatile int v;
Run Code Online (Sandbox Code Playgroud)

和线程A:

i = 1;
v = 2;
Run Code Online (Sandbox Code Playgroud)

和线程B:

vDst = v;
iDst = i;
Run Code Online (Sandbox Code Playgroud)

以下语句是否符合Java内存模型(JMM)?如果没有,那么正确的解释是什么?

  • i = 1总是发生在以前 v = 2
  • v = 2 发生 vDst = v在JMM 之前,只有它实际发生在时间之前
  • i = 1 发生 iDst = i在JMM 之前(并且iDst可以预测分配1)如果v = 2实际发生vDst = v在时间之前
  • 否则,在i = 1和之间的顺序iDst …

java volatile java-memory-model thread-synchronization happens-before

36
推荐指数
3
解决办法
2367
查看次数

Java volatile数组?

如何使数组易变?因为我已经明白了,使数组变得不稳定是不安全的吗?

java volatile

16
推荐指数
3
解决办法
5684
查看次数

如果不需要该值,Java 是否允许优化掉易失性读取,同时删除同步之前发生的操作?

以下代码示例显示了一种常见方法,用于演示由于缺少发生之前关系而导致的并发问题。

private static /*volatile*/ boolean running = true;
    
public static void main(String[] args) throws InterruptedException {
    new Thread() {
        @Override
        public void run() {
            while (running) {
                // Do nothing
            }
        }
    }.start();
    Thread.sleep(1000);
    running = false;
}
Run Code Online (Sandbox Code Playgroud)

如果runningvolatile,程序保证在大约一秒后终止。但是,如果running不是volatile,则根本无法保证程序终止(因为在running这种情况下没有发生之前关系或保证变量更改的可见性),而这正是我的测试中发生的情况。

根据JLS 17.4.5,人们还可以通过写入和读取另一个volatile变量来强制执行发生前关系running2,如以下代码示例所示。

private static boolean running = true;
private static volatile boolean running2 = true;
    
public static void main(String[] args) throws InterruptedException {
    new Thread() …
Run Code Online (Sandbox Code Playgroud)

java multithreading volatile java-memory-model happens-before

16
推荐指数
1
解决办法
555
查看次数

易变量和其他变量

以下是经典Concurency in Practice:

当线程A写入volatile变量并且随后线程B读取相同的变量时,在写入volatile变量之前A可见的所有变量的值在读取volatile变量后变为B可见.

我不确定我是否真的能理解这句话.例如,在这种情况下所有变量的含义是什么?这是否意味着使用volatile也会对非易失性变量的使用产生副作用?
在我看来,这句话有一些我无法理解的微妙含义.
有帮助吗?

java concurrency multithreading volatile memory-visibility

14
推荐指数
2
解决办法
1390
查看次数

这种非标准Java同步模式是否有效?

假设我有两个运行方式:

  • 线程A在更新共享图像的像素的同时执行计算
  • 线程B定期读取图像并将其复制到屏幕上

线程A快速执行工作,比如说每秒100万次更新,所以我怀疑经常在锁/互斥锁/监视器上锁定和解锁是个坏主意.但是如果没有锁定并且无法建立从线程A到线程B的先发生关系,那么通过Java内存模型(JMM规范),线程B根本不能保证看到A对图像的任何更新.

所以我认为最小的解决方案是线程A和B在同一个共享锁上定期同步,但在synchronized块内部实际上不执行任何工作 - 这就是使模式非标准和可疑的原因.用半实半伪代码来说明:

class ComputationCanvas extends java.awt.Canvas {

    private Object lock = new Object();
    private int[] pixels = new int[1000000];

    public ComputationCanvas() {
        new Thread(this::runThreadA).start();
        new Thread(this::runThreadB).start();
    }

    private void runThreadA() {
        while (true) {
            for (1000 steps) {
                update pixels directly
                without synchornization
            }
            synchronized(lock) {}    // Blank
        }
    }

    private void runThreadB() {
        while (true) {
            Thread.sleep(100);
            synchronized(lock) {}    // Blank
            this.repaint();
        }
    }

    @Override
    public void paint(Graphics g) {
        g.drawImage(pixels, 0, 0);
    } …
Run Code Online (Sandbox Code Playgroud)

java multithreading synchronization java-memory-model happens-before

7
推荐指数
1
解决办法
95
查看次数

番石榴:MemoizingSupplier线程安全

番石榴供应商级包含MemoizingSupplier:

static class MemoizingSupplier<T> implements Supplier<T>, Serializable {
    final Supplier<T> delegate;
    transient volatile boolean initialized;
    // "value" does not need to be volatile; visibility piggy-backs
    // on volatile read of "initialized".
    transient T value;

    MemoizingSupplier(Supplier<T> delegate) {
      this.delegate = delegate;
    }

    @Override public T get() {
      // A 2-field variant of Double Checked Locking.
      if (!initialized) {
        synchronized (this) {
          if (!initialized) {
            T t = delegate.get();
            value = t;
            initialized = true;
            return t;
          }
        }
      }
      return value; …
Run Code Online (Sandbox Code Playgroud)

java concurrency guava

6
推荐指数
1
解决办法
614
查看次数

使用volatile来确保Java中共享(但不是并发)数据的可见性

我正在尝试实现LZ77的快速版本,我有一个问题要问你关于并发编程的问题.

现在我有一个final byte[] bufferfinal int[] resultHolder两个相同的长度.该计划执行以下操作:

  1. 主线程写入所有缓冲区,然后通知线程并等待它们完成.

  2. 单个工作线程处理缓冲区的一部分,将结果保存在结果持有者的同一部分中.工人的部分是独家的.之后,通知主线程并且工作人员暂停.

  3. 当所有工作者都暂停时,主线程读取resultHolder中的数据并更新缓冲区,然后(如果需要)该过程再次从第1点开始.

manager(主线程)中的重要事项声明如下:

final byte[] buffer = new byte[SIZE];
final MemoryHelper memoryHelper = new MemoryHelper(); 
final ArrayBlockingQueue<Object> waitBuffer = new ArrayBlockingQueue<Object>(TOT_WORKERS);
final ArrayBlockingQueue<Object> waitResult = new ArrayBlockingQueue<Object>(TOT_WORKERS);
final int[] resultHolder = new int[SIZE];
Run Code Online (Sandbox Code Playgroud)

MemoryHelper只是包装一个volatile字段并提供两种方法:一种用于读取它,另一种用于写入它.

Worker的run()代码:

public void run() {
    try {
        // Wait main thread
        while(manager.waitBuffer.take() != SHUTDOWN){
            // Load new buffer values
            manager.memoryHelper.readVolatile();

            // Do something
            for (int i = a; i <= b; …
Run Code Online (Sandbox Code Playgroud)

java concurrency multithreading volatile memory-visibility

3
推荐指数
1
解决办法
275
查看次数

volatile 是否给其他普通存储和加载一个发生之前的关系?

我有一个关于 volatile 发生在规则之前的问题,同样的问题也符合监控规则。根据易失性规则,易失性写入发生在任何后续读取之前。

我有以下可变写入和正常后续读取的示例。据我所知,这个易失性写入应该有一个 StoreStore 内存屏障,它将正常的存储刷新到内存中,以便其他进程可以看到它(根据 DougLea 关于 JSR-133 内存模型的食谱)。

所以我的问题是:是否还有一个额外的发生在规则之前,正常存储的操作 1 也发生在正常加载的后续操作 2 之前。

int a;
volatile int x;


public void action1(){
    a = 100;  --- normal store
    x = 123;  ---volatile store
}

public void action2{
    int k = a; ---normal load
}
Run Code Online (Sandbox Code Playgroud)

java

3
推荐指数
1
解决办法
80
查看次数

使用两个线程一次打印一个字母和数字

我正在处理下面的面试问题,我需要使用两个线程打印出字母和数字.一个打印字母(a,b,c ... z)和其他打印数字(1,2,3 ...... 26).现在我必须以这样的方式实现它,输出应该是:

a
1
b
2
...
...
z
26
Run Code Online (Sandbox Code Playgroud)

所以我想出了下面的代码一,没有同步,但由于某种原因它不打印最后一个字母表 z

class Output {
  private static final int MAX = 26;
  private static int count = 1;
  private static final Queue<Character> queue = new LinkedList<>(Arrays.asList(new Character[] {
      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
      's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}));
  private boolean isAlphabet = true;

  public void printAlphabet() {
    while (true) {
      if …
Run Code Online (Sandbox Code Playgroud)

java concurrency multithreading thread-safety

0
推荐指数
1
解决办法
265
查看次数