java同步我怎么能理解

java synchronized how can i understand it

提问人:1earing 提问时间:7/25/2023 最后编辑:1earing 更新时间:7/25/2023 访问量:54

问:

import java.util.ArrayList;
import java.util.List;

public class unsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 101; i++) {
            int finalI = i;
            new Thread(() -> {
                synchronized (list) {
                    list.add(Integer.toString(finalI));
                }
            }).start();
        }
//        Thread.sleep(100);
        System.out.println(list.size());
        String string = list.stream()
                .map(Integer::valueOf)
                .reduce(0, Integer::sum)
                .toString();
        System.out.println(string);
    }
}

输出: 93 5050 输出 2: 101 5050 我在列表上设置了同步锁,以确保 ArrayList 可以安全地添加信息,但是我打印出来的数字并没有我想象的那么多,然后我进行了累加操作,发现得到的值是正确的结果。 如果我改用方法,那就是正确的结果,我应该如何理解它?list.sizelist.stream.count()

Java 同步

评论

5赞 MadProgrammer 7/25/2023
当您尝试从列表中读取时,您启动的线程可能尚未完成
3赞 Andy Turner 7/25/2023
除了未完成的线程之外,您还需要同步对调用列表的访问和操作的持续时间,以保证 s 的可见性。list.size()list.stream()....toString()add
0赞 MadProgrammer 7/25/2023
^--- 这应该是一个答案
0赞 vivek 7/25/2023
您仅在线程执行中同步了列表,并且只有在线程开始执行并到达语句时才会出现。在您的情况下,由于有多个线程,因此根本没有到达所有线程的同步块。所以你想要的是同步完整的操作。在这种情况下,可以通过连接所有线程来实现。
0赞 vivek 7/25/2023
此外,为了回答你关于为什么当你使用 list.stream.count() 时它起作用的观点 - 它完全依赖于集合的底层实现,即你的例子中的 ArrayList。对于其他实现,行为可能会有所不同。您需要查看 Stream、Spliterators 等才能进一步了解。

答:

0赞 Andy Turner 7/25/2023 #1

这里有两个问题:

  1. 你启动线程,但你不等待它们完成,使用 Thread.join()

  2. 您不会将主线程对列表的访问与 and 调用同步。size()stream()

    请注意,ArrayList 的 Javadoc 说:

    如果多个线程同时访问一个 ArrayList 实例,并且至少有一个线程在结构上修改了列表,则必须在外部同步该列表。

    也许很容易忘记主线程是像其他线程一样的线程,因此您也需要在那里进行同步。