9
private ExecutorService exec = Executors.newSingleThreadExecutor(r -> {
    Thread t = new Thread(r);
    t.setDaemon(true); // allows app to exit if tasks are running
    return t ;
});

I understand the idea behind an executor but, the paramater r is confusing me. I used:

 final ExecutorService exec = Executors.newSingleThreadExecutor(r -> {
        Thread t = new Thread(r);
        System.out.println("Class of r: " + r.getClass()+ ". r to string: " + r.toString());
        System.out.println("Class of t: " + t.getClass() +". Name of t: "+ t.getName());
        t.setDaemon(true);
        return t;
    });

to dig deeper and the result is:

Class of r: class java.util.concurrent.ThreadPoolExecutor$Worker. r to string: java.util.concurrent.ThreadPoolExecutor$Worker@1dc3963[State = -1, empty queue]
Class of t: class java.lang.Thread. Name of t: Thread-3

r is being passed as a parameter to the Thread object constructor.

  1. How is the simple letter r indicating that the object being passed is a ThreadPoolExecutor?
  2. How is a ThreadPoolExecutorpassable as a parameter if it does not implement Runnable as required by the by Thread's constructor?

If someone could provide me with a non-lambda version of the code as well, it would be of great benefit to my understanding.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
user465001
  • 806
  • 13
  • 29

1 Answers1

17

newSingleThreadExecutor takes a ThreadFactory as an argument. ThreadFactory defines a single method newThread that takes a Runnable as an argument and returns a Thread.

The lambda may make more sense to you if we specify the type of r explicitly:

(Runnable r) -> {
    Thread t = new Thread(r);
    return t;
}

Now it is more obvious this is a definition for the body of newThread.

Except that since the lambda is immediately passed as an argument to a method that accepts a ThreadFactory, the compiler is able to infer that the type of r must be Runnable. Therefore it can be omitted.

Without the lambda, this code translates to the following anonymous class definition and instantiation:

private ExecutorService exec = Executors.newSingleThreadExecutor(
    new ThreadFactory() {
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setDaemon(true);
            return t;
        }
    }
);

How is the simple letter r indicating that the object being passed is a ThreadPoolExecutor?

The type of r is Runnable because the target type of the lambda expression defines its single method that way.

The object you are seeing passed is actually a ThreadPoolExecutor$Worker which is a private inner class of ThreadPoolExecutor that implements Runnable.

How is a ThreadPoolExecutor passable as a parameter if it does not implement Runnable as required by the by Thread's constructor?

See above (r is a Runnable).

Radiodef
  • 37,180
  • 14
  • 90
  • 125
  • Thanks, Radiodef. I fully understand the code now. Where can I learn more about `outerclass$innerclass` type notations - the Java Language Specification? – user465001 Nov 06 '14 at 03:40
  • 3
    I'm glad to explain it. Also there is not a whole lot more to learn about the `$`. When you refer to a nested or inner class in the code you use `Outer.Inner` but typically it is actually compiled to a class called `Outer$Inner`. The `$` is a valid character for all identifiers but it is usually considered reserved for internal mechanisms. http://stackoverflow.com/q/7484210/2891664 – Radiodef Nov 06 '14 at 03:44
  • 4
    You may see dollar signs at other classes too, e.g. when you see a class name like `ClassContainingLambda$$Lambda$1`, it’s not an inner class… – Holger Nov 06 '14 at 14:05