-1

I have a class that represent the world where subjects live in

public class WorldLifecycle {
    private ExecutorService executorService;

    public void startWorld() {
        executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(),
            r -> {
                String id = ((IdentifiableRunnable) r).getId();
                return new Thread(r, id);
            });
    }

    public void bringLife(LivingPerson ... people) {
        Arrays.stream(people).forEach(executorService::submit);
    }

    public void endWorld() {
        executorService.shutdownNow();
        try {
            executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        } catch (InterruptedException e) {
            System.err.println("Failed to finish thread executor!");
        }
    }
}

Every LivingPerson looks like this

public class LivingPerson implements IdentifiableRunnable {
    // investigate global world variable
    private boolean isRunning = true;

    private final StatefulPerson person;

    public LivingPerson(StatefulPerson person) {
        this.person = person;
    }

    @Override
    public void run() {
        System.out.println("Initial state: person=" + person.getRawPerson());
        while (isRunning) { // for now forever
            try {
                Thread.sleep(1000); // do transition every 1 seconds

                LifeState state = person.nextState();
                System.out.println(getPerson().getName() + " " + state.getActionLabel());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        System.out.println("End state: person=" + person.getRawPerson());
    }

    @Override
    public String getId() {
        Person person = getPerson();
        return person.getId() + " - " + person.getName();
    }

    @Override
    public void terminate() {
        isRunning = false;
    }

    // returns clone instead of existing
    private Person getPerson() {
        return person.getRawPerson();
    }

}

I want to name each thread by using person's name and unique identifier.

IdentifiableRunnable is a simple interface

public interface IdentifiableRunnable extends Runnable {
    String getId();
    void terminate();
}

I initialize everything like this

WorldLifecycle world = new WorldLifecycle();
LivingPerson male = createPerson("John", 40, Gender.MALE);
LivingPerson female = createPerson("Helen", 25, Gender.FEMALE);

System.out.println("Starting world...");
world.startWorld();

world.bringLife(male, female);

// just wait
try {
    Thread.sleep(10000);
} catch (InterruptedException e) {
    throw new RuntimeException(e);
}

System.out.println("Destroying world...");
world.endWorld();

But when I try to run it, I get the error

Exception in thread "main" java.lang.ClassCastException: java.util.concurrent.ThreadPoolExecutor$Worker cannot be cast to com.lapots.breed.lifecycle.api.Ide
ntifiableRunnable
at com.lapots.breed.lifecycle.WorldLifecycle.lambda$startWorld$0(WorldLifecycle.java:14)
at java.util.concurrent.ThreadPoolExecutor$Worker.<init>(ThreadPoolExecutor.java:612)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:925)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1357)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at com.lapots.breed.lifecycle.WorldLifecycle.bringLife(WorldLifecycle.java:20)
at com.lapots.breed.Sandbox.main(Sandbox.java:23)

As it seems it does not get my identifiableRunnable in the ThreadFactory. How to solve it?

lapots
  • 12,553
  • 32
  • 121
  • 242
  • Not your down-voter, but in the future, please consider posting a valid [mcve]. Your code above has much bloat that is completely unrelated to the problem at hand, and you could reproduce the problem with 1/4 the code you've given. – Hovercraft Full Of Eels Jun 24 '18 at 15:15
  • Out of curiosity, what will you be using the thread id's for? I have to wonder if this is an [XY Problem](http://xyproblem.info/) in disguise. – Hovercraft Full Of Eels Jun 24 '18 at 15:26
  • @HovercraftFullOfEels I have no particular use for ids though for now. But decided to set them just in case if a `living person` fails due to some issue - easier to track which character's behavior is odd. – lapots Jun 24 '18 at 15:44

1 Answers1

1

If you trace library calls with a debugger you will notice that your newThread method will be called like so:

Worker(Runnable firstTask) {
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this);
}

So it is passed an instance of the Worker class, which obviously can't be cast to your IdentifiableRunnable.

To execute your stream in parallel you should use ForkJoinPool how it is described in this post, in the first answer Custom thread pool in Java 8 parallel stream

Btw, here's how you can compress the code in your post:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.stream.Stream;

public class Main {

    interface TestInterface extends Runnable{
        default String getId() {
            return "2";
        }
    }
    static class TestClass implements TestInterface {

        @Override
        public void run() {
            System.out.println("TEST");
        }
    }

    public static void main(String[] args) {
        ExecutorService exec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactory() {
            @Override
            public Thread newThread(final Runnable r) {
                String id = ((TestInterface)r).getId();
                Thread t = new Thread(r, id);
                t.setDaemon(true);
                return t;
            }
        });

        Stream.of(new TestClass(),new TestClass(),new TestClass(),new TestClass()).forEach(exec::submit);

    }
}
Coder-Man
  • 2,391
  • 3
  • 11
  • 19