首页 > 解决方案 > 多个线程何时访问相同的代码?

问题描述

我的问题是:

  1. 默认情况下,Java 程序是否只创建 1 个线程?
  2. 如果是,并且如果我们创建一个多线程程序,多个线程何时访问 Java 对象的相同代码?

例如,我有一个带有 2 个方法的 Java 程序 - add() 和 sub()。在什么情况下 2 个或更多线程会运行 'add()' 方法?

代码不总是线程安全的,因为多个线程将访问不同的代码部分吗?

如果不是,请展示一个关注线程安全的示例程序。

标签: javamultithreadingthread-safety

解决方案


不要考虑“代码段”,要考虑数据所在的位置以及有多少线程正在访问该实际数据。

  • 局部变量存在于它们正在使用的线程的堆栈中,并且是线程安全的,因为它们是每个线程的不同数据“容器”。

  • 任何存在于堆上的数据,例如实例或静态字段,本质上都不是线程安全的,因为如果多个线程访问该数据,那么它们可能会发生争用。

我们可以变得更复杂,并讨论数据的真正位置,但这个基本解释应该让您对正在发生的事情有一个很好的了解。

下面的代码给出了一个由两个线程共享的实例的示例,在这种情况下,两个线程都在访问同一个数组列表,它指向堆中相同的数组数据容器。运行几次,你最终会看到失败。如果您注释掉其中一个线程,它每次都会正常工作,从 99 开始倒计时。

import java.util.ArrayList;
import java.util.List;
public class Main {
    public static void main(String[] args) {
        MyRunnable r = new MyRunnable();
        new Thread(r).start();
        new Thread(r).start();
    }
    public static class MyRunnable implements Runnable {
        // imagine this list living out in the heap and both threads messing with it
        // this is really just a reference, but the actual data is in the heap
        private List<Integer> list = new ArrayList<>();
        {  for (int i = 0; i < 100; i++) list.add(i);  }

        @Override public void run() {
            while (list.size() > 0) System.out.println(list.remove(list.size() - 1));
        }
    }
}

推荐阅读