使用Runnable通过多个线程运行方法

时间:2017-05-19 11:43:18

标签: java multithreading runnable

在我的程序中,我想在其中一个方法中创建多个线程,其中每个线程必须运行具有给定输入的特定方法。使用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()中,我创建了一个列表数组并将项目放入其中。然后我想创建线程并将每个列表传递给方法。可以将数组和列表定义为私有类成员。但是,我想以这种方式做到这一点。

一切似乎都很正常,但是,在调用pleasePrint()时出现此错误:

error: local variables referenced from an inner class must be final or effectively final
      pleasePrint( ls[i] );

我该如何解决?

2 个答案:

答案 0 :(得分:1)

首先,你会在这里得到一个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

这是因为您无法从本地类访问非最终(或有效最终)变量。

'ls'实际上是最终的,但可能是因为你已经用两行来定义它,编译器无法注意到它。

答案 1 :(得分:1)

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

在此处引用Guy Steele

  

实际上,原型实现确实允许非最终变量   从内部类中引用。引起了强烈抗议   用户,抱怨他们不想要这个!原因很有趣:为了支持这些变量,有必要   堆分配它们,并且(至少在那时)至少是普通的Java   程序员仍然对堆分配和垃圾感到不安   收集等等。他们不赞成语言表演   当没有出现时,堆分配“在表下”   “新”关键词即将到来。

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

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

希望这会有所帮助:)