0
public class SemActionPlace {

    public SemMonitor StartConsumerProducer() {
        SemMonitor monitor = new SemMonitor();
        List<Thread> threads = new LinkedList<>();
        Thread p1 = new Thread(new Producer(monitor), "P1");
        p1.start();
        Thread c1 = new Thread(new Consumer(monitor), "C-odd");
        c1.start();
        Thread c2 = new Thread(new Consumer(monitor), "C-even");
        c2.start();
        threads.add(p1);
        threads.add(c1);
        threads.add(c2);
        for (Thread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return monitor;
    }
}

the code work just fine when I start thread through start() - join(), however, I failed to find mistake when I try to do the same through the executor service. It's important for me to save names of the threads and mutual monitor. Please, tell me how can I execute the threads through the executor service ?

The piece of code below doen't work properly. Where is mistake ?

public SemMonitor StartConsumerProducer() {
    SemMonitor monitor = new SemMonitor();
    Thread p1 = new Thread(new Producer(monitor), "P1");
    Thread c1 = new Thread(new Consumer(monitor), "C-odd");
    Thread c2 = new Thread(new Consumer(monitor), "C-even");
    ThreadPoolExecutor service = (ThreadPoolExecutor) Executors.newFixedThreadPool(3);
    service.execute(p1);
    service.execute(c1);
    service.execute(c2);
    System.out.println(service.getCompletedTaskCount());
    System.out.println(service.getCompletedTaskCount());
    return monitor;
}

I need one simple thing from the executor server is that I wanna that it works like simple start() - join() solution works ( first piece of code ) .

class Consumer implements Runnable {

    private final SemMonitor monitor;

    Consumer(SemMonitor monitor) {
        this.monitor = monitor;
    }

    @Override
    public void run() {
        long t = System.currentTimeMillis();
        long end = t + 1000;
        while (System.currentTimeMillis() < end) {
            consoleLog(monitor.activeThreadName,false);
            if (/*monitor.semaphore.tryAcquire() && */monitor.activeThreadName.equals( Thread.currentThread().getName())) {

                try {
                    consoleLog(String.valueOf(Thread.currentThread().getName() + " was notified "),monitor.enableLog);
                    monitor.semaphore.acquire();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                monitor.get(Thread.currentThread().getName());
            }
            try{
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        }

    }
}

class Producer implements Runnable {

    private SemMonitor monitor;

    Producer(SemMonitor monitor) {
        this.monitor = monitor;
    }

    @Override
    public void run() {
        String threadNameToWork;
        Integer randNum;
        long t = System.currentTimeMillis();
        long end = t + 500;
        while (System.currentTimeMillis() < end) {
            if (monitor.semaphore.tryAcquire()) {
                randNum = ((Number) (random() * 100)).intValue();
                if (randNum % 2 == 0) {
                    threadNameToWork = "C-even";
                } else {
                    threadNameToWork = "C-odd";
                }
                try {
                    monitor.putItem(randNum, Thread.currentThread().getName(), threadNameToWork);
                    Thread.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class Monitor {

    private double currItem;
    private boolean isConsumersShouldWaitProducer = true;
    private boolean isConsuming = false;
    private String threadNameToWork;

    synchronized void putRandNumber(double producerOutput, String producerName, String threadNameToWork) {
        if (isConsumersShouldWaitProducer) {
            System.out.println("Consumers wait for new Production");
        }
        this.threadNameToWork = threadNameToWork;
        currItem = producerOutput;
        System.out.println("Producer " + producerName + " putRandNumber Item: " + currItem);
        if (currItem > 3) {
            notifyAll();
            isConsumersShouldWaitProducer = false;
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    synchronized void consumeRandNumber(String threadName) {
        if (isConsumersShouldWaitProducer) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                System.out.println("Caught Interrupted Exception while waiting to consume currItem: " + e.getMessage());
            }
        }
        if (isConsuming) {
            try {
                this.wait();
                isConsuming = true;
            } catch (InterruptedException e) {
                System.out.println("Caught Interrupted Exception while waiting to consume currItem: " + e.getMessage());
            }
        }
        switch (Thread.currentThread().getName()) {
        /*switch (threadNameToWork) {*/
            case "C-odd":
                isConsuming = true;
                if (currItem % 2 != 0 && threadNameToWork.equals(Thread.currentThread().getName())) {
                    consumeItems(threadName);
                }
                isConsuming = false;
                notifyAll();
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                break;
            case "C-even":
                isConsuming = true;
                if (currItem % 2 == 0 && threadNameToWork.equals(Thread.currentThread().getName())) {
                    consumeItems(threadName);
                }
                isConsuming = false;
                notifyAll();
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                break;
            default:
                break;
        }
    }

    private synchronized void consumeItems(String threadName) {
        isConsumersShouldWaitProducer = true;
        String randNumType = "*odd/even*";
        System.out.println("Consumer:" + threadName + " consumed " + randNumType + " Items = " + currItem);
        notifyAll();
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • 2
    How about telling us what "doesn't work properly" means. – Kayaman Mar 29 '17 at 16:50
  • Thanks for your attention. I mean executor service doen't work in the same way as simple thread start() - join() methods work –  Mar 29 '17 at 16:59
  • Uh, yeah. So **how** doesn't it work the same way? – Kayaman Mar 29 '17 at 17:03
  • Okey. During one second the producer generates random number if number is odd the thread with name "C-odd" consumes the number, if number is even threa with name "C-even" consumes the number. When the second is over, I return monitor with data member that contains log what thread consume what number. At the end, send this log to the unit test. The end. –  Mar 29 '17 at 17:08
  • Thread pool executors don't execute threads. Instead, they execute tasks, either `Runnable` or `Callable`. So you don't have to create the threads, that is automatically done for you inside the executor. You also need to shutdown the executor and wait until all tasks are completed. – fps Mar 29 '17 at 17:11
  • @FedericoPeraltaSchaffner Thread implements Runnable interface, so in theory, it is validated for JVM – Yang Mar 29 '17 at 17:14
  • Amazing how you've still managed to avoid telling how the code with executor is behaving differently from the code with start/join. Third time's the charm? And yea, it would be cleaner to use `Runnable` and not `Thread` for the executor. – Kayaman Mar 29 '17 at 17:15
  • @FedericoPeraltaSchaffner yeah, thx for attention. However, my business logic depend on the name of the threads could you at least tell me how can I create three thread through executor service with unique names like I need ? –  Mar 29 '17 at 17:16
  • 1
    Relying on a thread name is really bad design. You could do an ugly hack with a `ThreadFactory`, but the best way would be to fix your design. – Kayaman Mar 29 '17 at 17:18
  • @Kayaman I was about to say exactly the same. – fps Mar 29 '17 at 17:19
  • @Kayaman It just doen't do what I need. For example, the first piece of code return to my 79 - 85 logs ( number plus the name of thread that handle it ) the second piece of code return to me 0 logs. I cannot debug into executor service ( probably should have IDEA Ultimate Edition IDE ) , I don't know the undercover problem. –  Mar 29 '17 at 17:19
  • @Kayaman how the ugly hask with ThreadFactory will be look like ? It just play exercise. I've much time to redesign the solution. Could you give me a clue ? Cause I saw only example with single thread ... but how to put 3 threads to ThreadFactory and then put the factory into executor service ??? –  Mar 29 '17 at 17:24
  • @Yang True, `Thread` implements `Runnable`. However, there's no need to create extra threads, which are not precisely cheap. – fps Mar 29 '17 at 17:25
  • @BernardCasey Please post the code of `Consumer` and `Producer`, along with the output, and clearly explain the expected results vs the actual results. – fps Mar 29 '17 at 17:27
  • Too ugly to bother really. Besides, it sounds like you don't really need to care about the thread's name. If you're using it for logging, you could give a name to your `Consumer` and `Producer` classes instead. – Kayaman Mar 29 '17 at 17:33
  • @Kayaman but I have 2 consumer ... So if you mean use Class name for business logic reaction it probably doen't help –  Mar 29 '17 at 17:39
  • I didn't suggest to rename classes, that would be even worse than what you have now. Or go for Yang's suggestion. – Kayaman Mar 29 '17 at 17:48

1 Answers1

0

You want to do something with Thread name right? The thread name you created in using new Thread will not pass into ExecutorService, but this will

ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
                                       .setNameFormat("thread-%d").build()

Then

ExecutorService exec = Executors.newSingleThreadExecutor(namedThreadFactory);

Now you have thread with name as thread-1, thread-2

OR set thread name in your run() method

Thread.currentThread().setName(myName)

To make sure your thread is finished, add this before you return the monitor,

service.shutdown();
while (!service.awaitTermination(10, TimeUnit.SECONDS)) {
   log.info("Awaiting completion of threads.");
}
Yang
  • 858
  • 6
  • 22
  • unfortunately didn't help –  Mar 29 '17 at 16:57
  • yeah, but how should I know what thread will be producer ( thread-1 ; thread- 2 or thread - 3 ) and which two will be consumers ? I believe the should be the better way for naming ... May there is the way to rename the threads after we create Executors.newFixedThreadPool(3) ??? –  Mar 29 '17 at 17:32
  • @BernardCasey edited `Thread.currentThread().setName(myName)` – Yang Mar 29 '17 at 17:35
  • So I probably need some kind of switch case for renaming in monitor class ... yeah ? –  Mar 29 '17 at 17:41
  • @BernardCasey There are many ways to pass name into `run()` method, one option is that you can create` Public void setMyThreadName(myName){ this.myName = myName;}` method which save `myName` as an instance variable in your `Producer`, then in your `run()` method, just use` Thread.currentThread().setName(this.myName)` – Yang Mar 29 '17 at 17:47