简体   繁体   English

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

[英]Does this non-standard Java synchronization pattern work?

Let's say I have two threads running like this: 假设我有两个运行如下的线程:

  • Thread A which performs computation while updating pixels of a shared image 线程A在更新共享图像的像素的同时执行计算
  • Thread B periodically reads the image and copies it to the screen 线程B定期读取图像并将其复制到屏幕上

Thread A performs work quickly, say 1 million updates per second, so I suspect it would be a bad idea to lock and unlock on a lock/mutex/monitor that often. 线程A快速执行工作,比如说每秒100万次更新,所以我怀疑经常在锁/互斥锁/监视器上锁定和解锁是个坏主意。 But if there is no lock and no way of establishing a happens-before relation from thread A to thread B, then by the Java memory model (JMM spec) thread B is not guaranteed at all to see any of A's updates to the image. 但是如果没有锁定并且无法建立从线程A到线程B的先发生关系,那么通过Java内存模型(JMM规范),线程B根本不能保证看到A对图像的任何更新。

So I was thinking that the minimum solution is for threads A and B to both synchronize periodically on the same shared lock, but not actually perform any work while inside the synchronized block - this is what makes the pattern non-standard and dubious. 所以我认为最小的解决方案是线程A和B在同一个共享锁上定期同步,但在synchronized块内部实际上不执行任何工作 - 这就是使模式非标准和可疑的原因。 To illustrate in half-real half-pseudo code: 用半实半伪代码来说明:

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);
    }
}

Does adding empty synchronization blocks in this way correctly achieve the effect of transferring data from thread A to thread B? 以这种方式添加空同步块是否正确地实现了将数据从线程A传输到线程B的效果? Or is there some other solution I failed to imagine? 还是有其他一些我无法想象的解决方案?

Yes it works. 是的有效。 But it works horribly. 但它的工作非常糟糕。

Happens before only works when the release of the writer happens before the acquire of the reader. 只有当作者的发行在读者获得之前发生时才会发生。 Your implementation assumes that whatever you're writing will complete before the subsequent reading/updating from ThreadB . 您的实现假定您正在编写的任何内容都将在随后从ThreadB读取/更新之前完成。 Causing your data to be flushed all the time by synchronized will cause performance problems, although to what extent I cannot say for sure. 导致您的数据一直被同步刷新将导致性能问题,尽管我无法肯定地说。 Sure, you've made your synchronization finer grained, have you tested it yet? 当然,你已经让你的同步更精细,你测试过了吗?

A better solution might use a singleton/transfer SPSC (single producer/single consumer) queue to store the current snapshot of the writing thread and use that whenever you update. 更好的解决方案可能是使用单例/传输SPSC(单个生产者/单个使用者)队列来存储写入线程的当前快照,并在每次更新时使用它。

int[] data = ...
Queue<int[]> queue = new ...

// Thread A
while (true) {
    for (1000 iterations or so) {
        ...
    }
    queue.add(data);
}

// Thread B
while (true) {
    int[] snapshot = queue.take(); 
    this.repaint();
}

The advantage of this is that you don't need to busywait, you can just wait for the queue to block or until the next write. 这样做的好处是你不需要忙碌,你可以等待队列阻塞或直到下一次写入。 You can skip writes that you don't have time to update. 您可以跳过没有时间更新的写入。 You don't need to depend on the arbitrary thread scheduler to plan data flushes for you. 您无需依赖任意线程调度程序来为您规划数据刷新。

Remember that thread-safe data structures are great for passing data between threads. 请记住,线程安全的数据结构非常适合在线程之间传递数据。

Edit: oops, forgot to say that depending on how your updates go, you might want to use an array copy to prevent your data from being garbled from random writes that aren't cached. 编辑:oops,忘了说根据您的更新的方式,您可能希望使用数组副本来防止您的数据因未缓存的随机写入而出现乱码。

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

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