Using Runnable to run a method by multiple threads

2019-09-07 02:38发布

In my program, I want to create multiple threads in one of the methods where each thread has to run a specific method with a given input. Using Runnable, I have written this snippet.

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();
  }
}

Please note, my big code looks like this. I mean in one method, doProcess(), I create an array of lists and put items in it. Then I want to create threads and pass each list to a method. It is possible to define the array and lists as private class members. But, I want to do that in this way.

Everything seems to be normal, however, I get this error at calling pleasePrint():

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

How can I fix that?

2条回答
萌系小妹纸
2楼-- · 2019-09-07 03:08

First to that, you will get a NullPointerException here:

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

Before, yo must instantiate the lists:

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

About the compiler error, try to define the array as final. Change:

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

By:

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

This is because you can't access to non-final (or effectively final) variables from a local class.

'ls' is effectively final but probably, since you have defined it in two lines, the compiler is not able to notice that.

查看更多
女痞
3楼-- · 2019-09-07 03:18

The reason you are getting this error is straightforward and clearly mentioned - local variables referenced from an inner class must be final or effectively final. This is, in turn, because, the language specification says so.

Quoting Guy Steele here:

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.

As far as your implementation goes, instead of using an array of list, I'd rather use a list of lists.

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

You can create new lists and insert them into the main list in the constructor depending on the number of lists you want.

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

You can then change your doProcess() method as follows:

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();
    }
}

Note: I used an instance variable named noOfLists to (as the name suggests) store the number of lists I need. Something as follows:

private final int noOfLists;

To populate the list, you could do:

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...

And you'll get the output something as:

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

Hope this helps :)

查看更多
登录 后发表回答