【问题标题】:Java - Filling an ArrayList of Threads with loopJava - 用循环填充线程的 ArrayList
【发布时间】:2013-08-27 01:32:59
【问题描述】:

这个问题可能很容易回答,但我就是不明白。 我减少了我的问题,直到留下一小段代码以找到这个问题的“起源”: 我正在尝试用循环填充线程的 ArrayList。

public static int u=0;

public void test(){
    while (u <10) {
        synchronized(threadList){
            threadList.add(u, new Thread(){                
                @Override public void run(){                    
                    System.out.println("Thread at Index: " + u);                     
                } 
            });
        }
        u++;            
    }

    threadList.get(2).start();    
}

在最后一行中,我想通过在索引“2”处启动线程来测试上面的循环。 我希望控制台显示“索引处的线程:2”,但显示的是: “索引处的线程:10” 无论我在“.get(int)”方法中写入哪个整数,我都会收到索引'10'。

这是为什么呢?以及如何解决这个问题?

线程的创建似乎工作......整数'u'是问题吗?

感谢任何形式的帮助! 提前致谢!

【问题讨论】:

  • u 是静态的,因此您将始终获得当前值(10 当您的程序运行时)。您没有保存在任何地方创建线程时使用的值。
  • 如果你的线程列表只从一个线程(主线程?)访问,你不需要同步使用它。

标签: java multithreading arraylist


【解决方案1】:

当您在 run 方法中引用 u

@Override public void run(){                    
    System.out.println("Thread at Index: " + u);                     
} 

检索u 的当前值。在循环结束和线程运行时,该值为10

试试下面的

public static int u = 0;

public void test(){
    while (u <10) {
        synchronized(threadList){
            threadList.add(u, new Thread(){     
                int i = u;

                @Override public void run(){                    
                    System.out.println("Thread at Index: " + i);                     
                } 
            });
        }
        u++;            
    }

    threadList.get(2).start();    
}

在您的匿名 Thread 类中,您将实例字段 i 设置为调用构造函数时 u 的值,并在执行 run() 时打印该值。

您在尚未执行的上下文(线程)中引用u。当 run() 方法最终被调用时,程序将评估变量 u,但在程序执行的那一刻,它的值将是 10。如果你执行上述操作,变量 @987654334 @ 将在那个确切时刻保存该值。这是因为当新的Thread 启动并执行时,会发生字段初始化,并且会立即评估u

【讨论】:

  • 感谢您的快速答复。是的,它有效!谢谢!但我真的不明白为什么它确实适用于“int i”。 ..是否因为 int u 是静态的并且在方法外部定义并且 int i 停留在方法内部无法从外部访问,因此在循环运行时它始终具有特定值?对不起我的英语不好。
  • 对像这样的小型 Runnables 进行小幅改进 - 将实例变量(在本例中为 i)设置为 final 以提高清晰度和线程安全性。
  • @user 在这种情况下,线程安全并不真正适用,因为我们正在处理一个匿名类。缺少反射,没有其他类可以访问该字段。
  • @Sotirios Delimanolis 啊,现在我明白了!非常感谢你的帮助! :)
  • 我总是(过度)担心过早出版(不是真正的术语,但你知道我的意思)。 Final 会解决这个问题。
【解决方案2】:

试试这两种方法:

package com.test;

import java.util.ArrayList;

public class TestThread5 {
    public static int u=0;
    public ArrayList<Thread> threadList = new ArrayList<>();
    public void test() throws InterruptedException{
        while (u <10) {
            synchronized(threadList){
                threadList.add(u, new Thread(){                
                    @Override public void run(){                    
                        System.out.println("Thread at Index: " + u);                     
                    } 
                });
            }
            u++;            
        }
        for ( u = 0; u < 10; u++) {
            Thread thread = threadList.get(u); 
            thread.start();
            thread.join();
        }
       // threadList.get(2).start();    
    }
    public static void main(String[] args) throws InterruptedException {
        new TestThread5().test();
    }
}

package com.test;

import java.util.ArrayList;
import java.util.Iterator;

public class TestThread4 {
    public  int u=0;
    public ArrayList<Thread> threadList = new ArrayList<>();
    public void test() throws InterruptedException{
        while (u <10) {
            synchronized(threadList){
                threadList.add(u, new MyThread(u));
            }
            u++;            
        }
        for(Thread thread :threadList){
            thread.start();
            thread.join();
        }
       // ((Thread) threadList.get(2)).start();    
    }
    public static void main(String[] args) throws InterruptedException {
        new TestThread4().test();
    }
}
class MyThread extends Thread{
    private int u;
    public MyThread(int u){
        this.u = u;
    }
    @Override
    public void run() {
        System.out.println("Thread at Index: " + u);  
    }

}

【讨论】:

    【解决方案3】:
        while (u <10) {
            synchronized(threadList){
    
                final int u_final = u;
    
                threadList.add(u, new Thread(){                
                    @Override public void run(){                    
                        System.out.println("Thread at Index: " + u_final );
                    } 
                });
            }
            u++;            
        }
    

    使用final 变量,很清楚它的值是什么,因为它永远不会改变。

    【讨论】:

    • 哦,我明白了..谢谢!所以,如果我理解一切正确:如果我使用 for 循环会更好,因为它带有一个循环变量(例如“int i = 0;”),它永远留在这个循环中并改变它仅在循环运行时才取值?
    • @MuSiCkiLL8or 您将无法直接在线程中使用 for 循环索引 i,因为它属于不同的范围。试试看,它不会编译。
    猜你喜欢
    • 2020-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-17
    • 1970-01-01
    • 2018-12-27
    • 2023-03-23
    相关资源
    最近更新 更多