Java多线程内for只执行一次

引言

多线程编程是计算机科学中的重要概念之一。它允许程序同时执行多个任务,提高了程序的性能和响应能力。Java作为一种广泛使用的编程语言,也提供了多线程编程的支持。然而,在多线程编程中,我们可能会遇到一些奇怪的现象,比如在多线程内部执行的for循环只执行一次。本文将介绍为什么会出现这种情况,并提供相应的代码示例进行解释。

问题描述

在多线程编程中,我们经常使用for循环来遍历一个集合或执行一段代码多次。然而,有时候我们会发现,在多线程的环境下,for循环只执行了一次,而不是我们预期的多次。这可能会导致程序逻辑错误或性能问题。下面是一个简单的代码示例:

public class Main {
    public static void main(String[] args) {
        Thread t1 = new Thread(new MyRunnable());
        Thread t2 = new Thread(new MyRunnable());
        
        t1.start();
        t2.start();
    }
}

class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ": " + i);
        }
    }
}

我们预期的输出应该是每个线程依次打印出0到4的数字,但实际上,输出可能是以下两种情况之一:

情况一:

Thread-0: 0
Thread-0: 1
Thread-0: 2
Thread-0: 3
Thread-0: 4
Thread-1: 0
Thread-1: 1
Thread-1: 2
Thread-1: 3
Thread-1: 4

情况二:

Thread-0: 0
Thread-1: 0
Thread-0: 1
Thread-1: 1
Thread-0: 2
Thread-1: 2
Thread-0: 3
Thread-1: 3
Thread-0: 4
Thread-1: 4

根据以上输出,我们可以发现,for循环只执行了一次,而不是我们预期的五次。那么,为什么会出现这种情况呢?

原因分析

在多线程编程中,每个线程都有自己的独立执行路径,称为线程栈。每个线程在执行时会从自己的线程栈中取得变量的副本进行计算。这就意味着,当多个线程同时访问同一个变量时,它们实际上操作的是各自的副本,而不是共享的原始变量。

在我们的代码示例中,每个线程都有自己的i变量副本,而不是共享的i变量。因此,每个线程在执行for循环时,实际上只执行了一次。这解释了为什么会出现for循环只执行一次的情况。

解决方法

为了解决for循环只执行一次的问题,我们需要使用一种机制来实现变量的共享。Java提供了一些同步机制,如synchronized关键字和ReentrantLock类,可以确保多个线程之间的顺序执行和互斥访问。下面是使用synchronized关键字修复代码示例的方法:

public class Main {
    public static void main(String[] args) {
        Thread t1 = new Thread(new MyRunnable());
        Thread t2 = new Thread(new MyRunnable());
        
        t1.start();
        t2.start();
    }
}

class MyRunnable implements Runnable {
    private static final Object lock = new Object(); // 用于同步的锁对象
    
    @Override
    public void run() {
        synchronized (lock) { // 使用锁对象进行同步
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + ": " + i);