首页 > 试题广场 >

有如下 Java 代码: public class Main

[不定项选择题]
有如下 Java 代码:
public class Main {
    private static int count = 0;
    public synchronized void increment() {
        count++;
    }
    public static void main(String[] args) {
        Main obj1 = new Main();
        Main obj2 = new Main();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1500; i++) {
                obj1.increment();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1500; i++) {
                obj2.increment();
            }
        });
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(count);
    }
}
则运行结果可能为()
  • 2911
  • 2634
  • 3000
  • 3015
这段代码存在线程安全问题,最终输出的count值可能小于预期的3000(1500+1500)。

问题分析:

  1. synchronized修饰实例方法的锁对象
    increment()是被synchronized修饰的实例方法,其锁定的是当前对象实例(this)。即:
    • 线程t1调用obj1.increment()时,获取的是obj1对象的锁;
    • 线程t2调用obj2.increment()时,获取的是obj2对象的锁。
    由于obj1和obj2是两个不同的对象,两个线程持有的是不同的锁,因此它们可以同时进入increment()方法,不存在互斥关系。
  2. 静态变量count的线程不安全操作
    count是static变量,属于类级别的共享资源,被所有实例共享。count++操作不是原子操作(包含 “读取 - 加 1 - 写入” 三个步骤)。
    当两个线程同时执行count++时,可能出现以下情况:
    • 线程 1 读取count=100,尚未完成加 1 写入;
    • 线程 2 同时读取到count=100,也执行加 1;
    • 最终两者都写入101,导致一次递增操作 “失效”。
发表于 2025-09-03 09:14:08 回复(0)

该Java代码存在线程安全问题,运行结果可能小于3000(即1500 + 1500),具体值不确定,但不会是3000。以下是详细分析:

代码问题分析:

  1. **共享变量count**:

    • count是一个静态变量(private static int count = 0;),因此它是类级别的,所有实例共享此变量。
    • 两个线程(t1和t2)都会修改count,每个线程执行1500次递增操作,理想情况下总增量应为3000。
  2. **synchronized方法无效**:

    • increment方法被声明为synchronized,但这意味着它锁定的是调用该方法的对象实例(例如,obj1或obj2的锁)。
    • 在main方法中,创建了两个不同的对象obj1和obj2:
      • t1调用obj1.increment(),获取obj1的锁。
      • t2调用obj2.increment(),获取obj2的锁。
    • 由于obj1和obj2是不同的对象,它们的锁互不干扰。因此,t1和t2可以同时进入increment方法,导致对静态变量count的访问没有真正的同步。
  3. 竞态条件(Race Condition)

    • count++操作不是原子性的。它涉及三个步骤:读取当前值、增加1、写回新值。
    • 当两个线程同时执行时,可能出现以下情况:
      • 线程A读取count为X。
      • 线程B也读取count为X(在A写回之前)。
      • 线程A写回X+1。
      • 线程B写回X+1(而不是X+2)。
    • 这导致一些增量丢失,最终count的值小于预期值3000。
  4. 线程执行

    • 使用t1.join()和t2.join()确保主线程等待两个子线程完成后再打印count,因此输出是最终值。
    • 但由于竞态条件,最终值不确定,具体取决于线程调度和执行的时机。

运行结果:

  • 可能的值:由于竞态条件,count的值可能为小于3000的任何整数,常见范围在 2800 到 2999 之间(取决于系统调度),但理论上可能低至1500(如果所有更新都丢失,但概率极低)。
  • 不可能的值:3000(因为同步无效,冲突不可避免),或0(线程正常执行,不会未启动)。
  • 示例输出:运行多次,可能得到不同结果,如 2999、2985、2870 等。

如何修复:

  • 要确保线程安全,应使用类级别的锁来保护静态变量:
    • 将increment方法改为静态并同步:public static synchronized void increment() { count++; }。
    • 或使用类锁:public void increment() { synchronized (Main.class) { count++; } }。
  • 修复后,运行结果将始终为3000。

总结:

运行结果可能为小于3000的整数(例如,2999、2980等),但不会是3000。这是由于实例级别的同步无法保护静态变量,导致竞态条件。

发表于 2025-09-20 21:01:53 回复(0)