当前位置: 首页 > 知识库问答 >
问题:

Java Synchronized:两个线程下的有线行为[重复]

宋臻
2023-03-14

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

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实例,同步只会阻止访问相同方法的线程。AKA如果线程A调用写数据,B使用读数据,它们不会相互影响(如果我错了,请纠正我)。

但是,当我试图用下面的代码演示它时:

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个答案

谭志用
2023-03-14

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

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

在调用<code>for</code>循环中的同步方法之间的代码中,有一个很小的时间段,其他线程可以在第一次进入readData()之前进入writeData()-<code>的典型<code>循环不是原子操作-但这个时间段很小,这种情况很少发生-所以你的输出看起来像是在以某种方式互相阻挡-在某一点上,风向发生了变化,其他线程占据了主导地位。

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

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();
                // any thread can now invoke writeData() if current thread is before next invocation of worker.readData();
            }

            try {
                Thread.currentThread().join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            System.out.println("start write thread");
            for (int i = 0; i < 20; i++) {
                worker.writeData();
                // any thread can now invoke readData() if current thread is before next invocation of worker.writeData();
            }

            try {
                Thread.currentThread().join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

如果您想要更好的交错,您可以执行以下操作之一:

    < li >使用wait()和notify() < li >不要对方法使用同步-同步数据。 < li >将sleep操作移出synchronized write和read方法,它们将为线程提供更多进入synchronized块的机会。
杜轩昂
2023-03-14

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

如果你希望你的输出是:

等等...

那么我建议使用wait()函数;和notifyAll();这样,您可以使线程A在线程B完成后转一圈,反之亦然。

您可以在这里阅读有关wait()和notifyAll()的更多信息。

司马项明
2023-03-14

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

不对。它阻塞试图在同一对象上同步的线程。

 类似资料:
  • 我如何启动两个线程,其中thread1首先执行,thread2在thread1结束时启动,而主方法线程可以在不锁定其他两个线程的情况下继续工作? 我尝试了join(),但是它需要从线程调用,线程必须等待另一个线程,没有办法执行类似thread2.join(thread1)的操作;因此,如果我在main()中调用join,我将有效地停止主线程的执行,而不仅仅是Thread2的执行。 #编辑:为什么我

  • 我有一个很大的表,大约1米的记录,我想对所有的记录做一些处理,所以1个线程的方式,就是说。。。1000条记录,处理它们,再获得1000条记录等等。。。但如果我想使用多任务处理呢?也就是说,两个线程分别获取1000条记录,并并行处理,如何确保每个线程将获取不同的1000条记录?注意:我正在使用hibernate 好像是这样的

  • 我有2个工作线程和1个处理线程。 当处理线程正在尝试处理某些事情,而辅助线程正在执行它们的工作时,处理线程应该等待,并且在辅助线程中执行的所有作业完成时唤醒。 我怎样才能唤醒这根线?我将尝试演示我在这段伪代码中的意思 处理线程类似于 这样的事情可能发生吗?让线程等待到多个调用notifyAll()的源,而不是只等待一次。我希望我把这个问题弄清楚了。 多谢帮忙!

  • 我试着运行一个程序,使用线程显示带有数字的乘法、除法、加法和减法表。 但是我希望数字被乘以或相加等。由用户选择。 也就是说,程序应该在用户为每个操作选择一个数字后运行,然后显示结果。

  • 我有一个python脚本,所以我在python中使用线程模块并发执行。 def run(self):db=MySQLdb。connect('localhost','mytable','user','mytable')游标=db。cursor()query=“dig short”str(反向ip)”按键try:output=子进程。检查\u输出(查询,shell=True)输出\u编辑=输出。条带(