使用 Runnable 到 运行 多个线程的方法

Using Runnable to run a method by multiple threads

在我的程序中,我想在其中一个方法中创建多个线程,其中每个线程都必须 运行 具有给定输入的特定方法。使用 Runnable,我写了这个片段。

class myClass {
  public myClass() { }
  public void doProcess() {
    List< String >[] ls;
    ls = new List[2];  // two lists in one array
    ls[0].add("1");  ls[0].add("2");  ls[0].add("3");
    ls[1].add("4");  ls[1].add("5");  ls[1].add("6");

    // create two threads 
    Runnable[] t = new Runnable[2]; 
    for (int i = 0; i < 2; i++) {
      t[ i ] = new Runnable() {
        public void run() {
          pleasePrint( ls[i] );
        }
      };
      new Thread( t[i] ).start();
    }
  }
  void pleasePrint( List< String > ss )
  {
    for (int i = 0; i < ss.size(); i++) {
      System.out.print(ss.get(i)); // print the elements of one list
    }
  }
}

public class Threadtest {
  public static void main(String[] args) {
    myClass mc = new myClass();
    mc.doProcess();
  }
}

请注意,我的大代码如下所示。我的意思是在一种方法中,doProcess(),我创建了一个列表数组并将项目放入其中。然后我想创建线程并将每个列表传递给一个方法。可以将数组和列表定义为私有 class 成员。但是,我想用这种方式来做。

一切似乎都很正常,但是,我在调用 pleasePrint():

时收到此错误
error: local variables referenced from an inner class must be final or effectively final
      pleasePrint( ls[i] );

我该如何解决?

首先,您将在此处得到 NullPointerException:

ls[0].add("1");  ls[0].add("2");  ls[0].add("3");
ls[1].add("4");  ls[1].add("5");  ls[1].add("6");

之前,你必须实例化列表:

ls[0] = new ArrayList<>();
ls[1] = new ArrayList<>();

关于编译器错误,尝试将数组定义为final。变化:

List< String >[] ls;
ls = new List[2];  // two lists in one array

作者:

final List< String >[] ls = new List[2];  // two lists in one array

这是因为您无法从本地 class.

访问非最终(或实际上最终)变量

'ls' 实际上是最终的,但可能,因为您在两行中定义了它,所以编译器无法注意到这一点。

您收到此错误的原因很简单且明确提及 - 从内部 class 引用的局部变量必须是最终的或实际上是最终的。反过来,这是因为语言规范是这样说的。

此处引用Guy Steele

Actually, the prototype implementation did allow non-final variables to be referenced from within inner classes. There was an outcry from users, complaining that they did not want this! The reason was interesting: in order to support such variables, it was necessary to heap-allocate them, and (at that time, at least) the average Java programmer was still pretty skittish about heap allocation and garbage collection and all that. They disapproved of the language performing heap allocation "under the table" when there was no occurrence of the "new" keyword in sight.

就您的实施而言,我宁愿使用列表的列表,而不是使用列表数组。

private final List<List<String>> mainList = new ArrayList<>();

您可以创建新列表并将它们插入到构造函数中的主列表中,具体取决于您想要的列表数量。

public ListOfLists(int noOfLists) {
    this.noOfLists = noOfLists;
    for (int i = 0; i < noOfLists; i++) {
        mainList.add(new ArrayList<>());
    }
}

然后您可以按如下方式更改 doProcess() 方法:

public void doProcess() {
    for (int i = 0; i < noOfLists; i++) {
        final int index = i;
        // Using Lambda Expression as it is much cleaner
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName());
            pleasePrint(mainList.get(index));   // Pass each list for printing
        }).start();
    }
}

注意: 我使用了一个名为 noOfLists 的实例变量来(顾名思义)存储我需要的列表数。内容如下:

private final int noOfLists;

要填充列表,您可以这样做:

mainList.get(0).add("1");
mainList.get(0).add("2");
mainList.get(0).add("3");
mainList.get(1).add("4");
mainList.get(1).add("5");
mainList.get(1).add("6");
// And so on...

你会得到如下输出:

Thread-0
1
2
3
Thread-1
4
5
6

希望这对您有所帮助:)