Java同步:两个线程下的有线行为

时间:2017-05-17 10:37:22

标签: java multithreading

我创建了一个简单的工人:

public class Worker {

    public synchronized void writeData() {
        try {
            System.out.println("write Data , thread id = " + Thread.currentThread().getId());
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void readData() {
        try {
            System.out.println("readData , thread id = " + Thread.currentThread().getId());
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

AFAIK,如果多个线程访问相同的Worker实例,则synchronized仅阻止访问相同方法的线程。 AKA如果线程A调用writeData而B使用readData,它们不会相互影响(如果我错了,请纠正我)。

但是,当我尝试通过以下代码演示它时:

private static void testWithThreads() {
        final Worker worker = new Worker();

        new Thread(() -> {
            System.out.println("start read thread");
            for (int i = 0; i < 20; i++) {
                worker.readData();
            }

        }).start();

        new Thread(() -> {
            System.out.println("start write thread");
            for (int i = 0; i < 20; i++) {
                worker.writeData();
            }

        }).start();
    }

我得到了这样的输出(注意我们这里有Thread.sleep 2秒钟):

start read thread
readData , thread id = 10
start write thread
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10

任何人都可以向我解释这个吗?它们似乎以某种方式相互阻挡。

3 个答案:

答案 0 :(得分:0)

方法级别上的

synchronized同步对方法所属的Object的所有同步方法的访问,只有一个线程可以在该对象的任何同步方法中执行。其他线程即使尝试访问除第一个线程之外的其他synchronized方法也会等待。

其他线程将阻塞,直到第一个线程从同步块中退出。

for循环中调用同步方法之间的代码中,有一个很小的时隙,其他线程可以在第一次再次进入readData()之前进入writeData() - 一个典型的{{ 1}}循环不是原子操作 - 但是这个时间段很小,很少发生 - 因此你的输出看起来像是以某种方式相互阻挡 - 并且在一点上风改变而其他线程起带头作用。

更具体地说,注释指向每个for循环中“非同步”时隙开始的位置:

for

如果你想要更好的交错,你可以做以下事情之一:

  • 使用wait()和notify()
  • 不要对该方法使用同步 - 同步 数据。
  • 在同步写入和读取方法之外移动睡眠操作, 他们会给线程更多的机会进入 synchronized block。

答案 1 :(得分:0)

  

synchronized仅阻止访问相同方法的线程

错误。它阻止尝试在同一对象上同步的线程。

答案 2 :(得分:0)

它的工作原理是如果A对Worker实例使用writeData,那么在有机会之前,B不能使用同一Worker的readData或writeData。

如果您希望输出为:

等...

然后我会建议使用函数wait();和notifyAll(); 通过这种方式,您可以使线程A在完成后给线程B一个转弯,反之亦然。

您可以阅读有关wait()和notifyAll()的更多信息 here