Thread Pools in Java

Поділитися
Вставка
  • Опубліковано 22 лис 2024

КОМЕНТАРІ • 123

  • @hiendinh3871
    @hiendinh3871 10 місяців тому +9

    This Java Concurrency and Multithreading playlist gonna be the favorite playlist of my nephews, my nieces and my children when they engage themself in Computer Science one day!

    • @JakobJenkov
      @JakobJenkov  10 місяців тому +3

      ... if the world hasn't changed radically by then !! :-D

  • @shubhamagarwal1434
    @shubhamagarwal1434 6 місяців тому +3

    God of Concurency..i have bene flowing you since my 2014 when you used to write blog post only...by going through your post i attend interview like a LION when they ask mutithreading qns..Thanks a Lot form 10+ yrs exp guy from BLR,India.

    • @JakobJenkov
      @JakobJenkov  6 місяців тому +2

      You are welcome !! ... I am happy that my tutorials were helpful to you over the years!! :-)

  • @TimurLee-on7sm
    @TimurLee-on7sm 6 місяців тому +2

    your explanation is so clear and the most important thing you show how it all works internally, thank you so much

    • @JakobJenkov
      @JakobJenkov  6 місяців тому

      You are welcome! Glad you liked it! :-) ... seeing how a component works internally demystifies it - and enhances your general knowledge level :-)

  • @shankar7435
    @shankar7435 5 місяців тому +1

    For a moment I thought ThreadPool was a Java standard class and wondered how I could miss this? Thank God. It's a custom one made by the author. No need to remember that. This should have been made it clear in the beginning.

  • @specialFuture-j9e
    @specialFuture-j9e 3 роки тому +3

    this is one of the most understandable explanation and easiest to understand video on the topic

  • @roman_mf
    @roman_mf 2 роки тому +3

    Thank you Jakob for making multithreading fun to learn!

    • @JakobJenkov
      @JakobJenkov  2 роки тому

      You are welcome ! Great to hear :-)

  • @computerlearningbyargusaca5217
    @computerlearningbyargusaca5217 4 роки тому +15

    Exactly what I was searching for .. extremely helpful

  • @alexa.2112
    @alexa.2112 3 роки тому +1

    Thanks a lot for your explanation. You've done a great job.
    For those java begginers as I who wants to try this code code on their machines I will suggest to do simple pause on PoolThreadRunnable class

    public void run(){
    this.thread = Thread.currentThread();
    while(!isStopped()){
    try{
    Thread.sleep(1000); //do simple pause there
    Runnable runnable = (Runnable) taskQueue.take();
    runnable.run();
    } catch(Exception e){
    //log or otherwise report exception,
    //but keep pool thread alive.
    }
    }
    }
    Then you will clearly saw that the all tasks evenly distributed by the number of threads. Because in my machine in 80% cases all work done on Thread-0.

  • @michaelfarhat4881
    @michaelfarhat4881 2 роки тому +4

    With this great and simple explanation I hope that you can make a tutorial about data structures in java.

    • @JakobJenkov
      @JakobJenkov  2 роки тому

      I might - but I am not sure I will have the time for that... but I might write textual tutorials about this topic. That might still be helpful for you... but I am no there yet.

  • @chadchad4908
    @chadchad4908 3 роки тому +6

    thank you sir! you really helped me alot . you surely deserve more attention !

  • @OODevelopers
    @OODevelopers 3 роки тому +3

    Thanks a lot to you. This multithreading tutorial is great. I understood a lot from this series. Can you please make videos on callable interface, future, future task classes even. Thanks in advance.

    • @JakobJenkov
      @JakobJenkov  3 роки тому +3

      Hi Siddireddy, thank you very much! I am happy you found this series useful ! ... yes, I will probably get into more depth about how to use more of the Java Concurrency interfaces and classes in future videos.

  • @grankoczsk
    @grankoczsk 3 роки тому +1

    Just what I was looking for

  • @IgorDomshchikov
    @IgorDomshchikov 5 місяців тому

    @JakobJenkov, thanks for the set of videos. Can you please provide more details about why the PoolThreadRunnable.doStop() and PoolThreadRunnable.isStopped() are synchronized? I am not sure I understand the purpose of this, as both are called from the synchronized methods of the ThreadPool instance.

    • @JakobJenkov
      @JakobJenkov  4 місяці тому +1

      That is to ensure thread visibility of the member variables set by these methods, for the threads running the Runnable instances.

    • @IgorDomshchikov
      @IgorDomshchikov 4 місяці тому

      @@JakobJenkov , thanks. The point was about the visibility. As I understand making isStopped variable volatile can be an alternative.

  • @menchomenchev8973
    @menchomenchev8973 2 роки тому +1

    outstanding content Jakob!

  • @bahadirgirtten
    @bahadirgirtten 2 роки тому +2

    Thanks for the example and explanation.
    Do you think there would be a better way to implement waitUntilAllTasksFinished ?
    The current implementation would interrupt the last task if it were a long one. i.e TaskQueue being empty does not mean the very last task has finished its job.

    • @JakobJenkov
      @JakobJenkov  2 роки тому

      Yes - if you wanted to implement a ThreadPool 100% robustly - you would probably make a few changes to it. However, if I did, the video would get pretty long, and the code long to show on the screen, so I left it as an exercise for the viewer to do ;-)

  • @kafychannel
    @kafychannel Рік тому +1

    Hello Jakob, thank you for your great tutorials !
    11:26
    Are you sure we should make execute to be synchronized?
    Can we just make stopped variable to be volatile ?
    I guess queue.offer() is already synchronized this is why we may not need execute() to be synchronized

    • @JakobJenkov
      @JakobJenkov  Рік тому +1

      It is possible that you could optimize the synchronization around some of the constructs in this video. I try to keep them as simple as possible to avoid confusing the viewer, meaning sometimes a construct might not be optimally implemented - if that optimization is not the purpose of the video.

  • @akhlaq87
    @akhlaq87 4 роки тому +5

    When would you use your own implantation or your approach instead of the ExecutorService from std lib?

    • @JakobJenkov
      @JakobJenkov  4 роки тому +7

      Only in a situation where the ExecutorService lacks some functionality that you need. Otherwise there is no big reason to implement your own thread pool. However, I have come across situations where I needed something slightly different, and in those situations it can be handy to know how to implement your own Thread Pool :-)

    • @akhlaq87
      @akhlaq87 4 роки тому

      @@JakobJenkov thanks for the reply and the great content

  • @tomsowyer4956
    @tomsowyer4956 2 роки тому +1

    Finally I got it )) Thanks

  • @zoltanzsurkai7725
    @zoltanzsurkai7725 Рік тому +1

    Hey Jacob. Why the tasks (that you add in the execute method in the main method) are Runnable implementations when you only call the run() method on those objects from the PoolThreadRunnable.run() method? So if I see correctly those Task objects could be any other (not Runnable) objects...right?

    • @JakobJenkov
      @JakobJenkov  Рік тому +2

      Yes - in theory the PoolThreadRunnable.run() method could call _any_ method in the task objects - if you changed the code to do so. I just used the run() method - because developers are used to the run() method of such tasks :-)

    • @zoltanzsurkai7725
      @zoltanzsurkai7725 Рік тому

      @@JakobJenkov Thanks for the confirmation!

  • @candemirhan01
    @candemirhan01 2 роки тому +1

    Hello sir, Thank you. That video series is what i was exatly looking for.

  • @andymejia545
    @andymejia545 Рік тому +1

    @JakobJenkov is there any difference between ExecutorService pattern and ThreadPool and which cases are those can be suitables for complexity execution task?

    • @JakobJenkov
      @JakobJenkov  Рік тому +1

      An ExecutorService is typically implemented using a thread pool of some sorts. No big difference. ExecutorService tends to have more functionality and more variants - that is all. Plus it is standard in Java.

  • @มักโชคดี
    @มักโชคดี Рік тому +1

    Hi Jacob, could you give us an implementation example of a threadPool using wait() and notify() instead of sleep(1). Thanks.

    • @JakobJenkov
      @JakobJenkov  10 місяців тому

      Hmm.... at some point I might ... but if you are just looking to use a ThreadPool - the built-in Java ExecutorService is probably a better choice than making your own!

    • @มักโชคดี
      @มักโชคดี 10 місяців тому

      @@JakobJenkov You are right, my software requires lots of evolutions at different points. for the moment a java executor does the job. I will need to create my own version but this can wait. I have many other parts of my software to make evolve before to come back on a better way to handle my thread pools. Th4n|

  • @devdesk
    @devdesk Рік тому +1

    Code is not working with 100 runnable tasks.working fine with 10 runnable tasks

    • @kafychannel
      @kafychannel Рік тому +2

      Hello ! I guess it is because Jakob uses offer() method - this.taskQueue.offer(task); instead of put() in his example.
      Offer method returns true if it is possible to put a task into the queue and false if not.
      Because Jakob creates thread pool with capacity of 10 tasks it works when he calls threadPool.execute() 10 times.
      If you increase count of execution inside for loop you also should increase capacity of the queue or use put() method. put() - When the queue is full threads will be waiting for space to become available and then put their tasks into the queue

  • @emmanuelreuven7350
    @emmanuelreuven7350 2 роки тому +1

    You are the best man, thank you

  • @redcrafterlppa303
    @redcrafterlppa303 2 роки тому

    Great video. Except for the busy waiting in the thread pool. I guess you used it for simplicity but you really shouldn't busy wait.

    • @JakobJenkov
      @JakobJenkov  2 роки тому +2

      "...but you really shouldn't busy wait." .
      I disagree. There are situations - especially in low latency programming - where busy waits make sense because the overhead of waking up a waiting thread is high.
      Also, if the load on the system is high, the busy waits typically won't last very long, and thus won't result in a huge overhead. You have to know what you design for - when designing high throughput, low latency, highly concurrent systems. And you have to measure performance a lot! The same designs may even perform differently on different types of hardware. There is no "one size fits all" in this area.
      In this case though, I did use busy wait for simplicity. The alternative would have been implementing some more complicated thread signaling mechanism where the PoolRunnable's signaled to the ThreadPool when they had finished their work. The ThreadPool could then check if there were more tasks left in its queue (size() > 0),
      and if not - notify the waiting thread that it could wake up. That is probably how you would do it if you were to implement a ThreadPool for an API. But here I was mostly showing a way to implement a thread pool - not "The Perfect ThreadPool implementation".

  • @ayushsatyavarpu6055
    @ayushsatyavarpu6055 Рік тому

    Hello Jakob! Thanks for the great video, I had a question regarding your implementation of the ThreadPool. I read over the code, and I am curious as to how race conditions are prevented here. Based on the code, could the case of two PoolThreadRunnable's both finish their run functions, then try to take the next runnable from the List? The only way I can see to prevent this is if the BlockingQueue's take method is synchronized, which I'm not sure if it is?

    • @JakobJenkov
      @JakobJenkov  Рік тому

      BlockingQueue is a concurrent data structure, so only one thread can take an element at a time.

  • @imr_07
    @imr_07 5 місяців тому

    First, thanks for all the in depth tutorials.
    When I'm submitting i < 100 tasks, why am not seeing 100 logged messages?

    • @JakobJenkov
      @JakobJenkov  5 місяців тому

      Does your code wait for the tasks to complete before exiting ?

    • @imr_07
      @imr_07 5 місяців тому

      @@JakobJenkov Yes, I call threadPool.waitUntilAllTaskFinished();
      public synchronized void waitUntilAllTaskFinished() {
      while (!queue.isEmpty()) {
      try {
      Thread.sleep(10);
      } catch (InterruptedException ex) {
      ex.printStackTrace();
      }
      }
      }
      It's only working correctly when I'm giving queue capacity == no. of tasks.

    • @imr_07
      @imr_07 5 місяців тому

      Issue is with this.queue.offer(task); inside execute() method. We need to wait before there is some space in the queue for adding more items.
      or using overloaded this.queue.offer(task, 100, TimeUnit.SECONDS);
      let me know if you think there is some other issue.

  • @shortsum
    @shortsum 3 роки тому +1

    is it possible that a thread can be preempted when it's inside it's critical section ? If yes what would happen in case the other thread is context switched, as this new thread would be unable to attain the lock as it's held by the preempted thread. All I am aware is if the executing thread is preempted before calling wait(), it doesn't release the lock.

    • @JakobJenkov
      @JakobJenkov  3 роки тому +2

      In theory, a thread could be preempted while inside a synchronized block, or while holding a Lock. However, no other thread can enter the synchronized block or take the Lock until the preempted thread wakes up again, and exits the synchronized block, or unlocks the Lock. When a thread is inside a synchronized block and calls .wait() on the object the synchronized block is synchronized on (the monitor object), then the thread is preempted and releases the "lock" on the monitor object, so other threads can enter blocks synchronized on the same monitor object.

  • @alibaba40thvs
    @alibaba40thvs Рік тому +1

    Please also create some lessons on ThreadGroup.

    • @JakobJenkov
      @JakobJenkov  Рік тому

      Hmm.... I might do that ! Thank you for the suggestion!

  • @fuadgafarov
    @fuadgafarov 3 роки тому +1

    thanks Jakob

  • @RaghuVN
    @RaghuVN 3 роки тому +1

    Great content, but I think it will be better if you do the implementation of threadpool before using it.

    • @JakobJenkov
      @JakobJenkov  3 роки тому +1

      You can always check out the description below the video and find a link to a textual version of this tutorial - then you can jump around the text as it fits your learning style :-)

  • @SuperSam4y0u
    @SuperSam4y0u 4 роки тому +2

    In PoolRunnable the Boolean variable is not volatile, will this not cause visibility problems? I saw that synchronised is there bt that is not enough rite? Pls let me know.

    • @SuperSam4y0u
      @SuperSam4y0u 4 роки тому

      The volatile concept has me thinking, if you have non final variables in a class and that class will be used by multiple threads then you should make it volatile.
      In addition if multiple threads are also changing(as in the reference) that variable, then make the write method with synchronisation.

    • @SuperSam4y0u
      @SuperSam4y0u 4 роки тому

      This explained it tutorials.jenkov.com/java-concurrency/java-happens-before-guarantee.html... i guess thanks

    • @JakobJenkov
      @JakobJenkov  4 роки тому +3

      If a variable is accessed from withing a synchronized block, then the variable does not need to be volatile, as synchronized blocks in Java have about the same visibility guarantees as a volatile variable.

  • @ThePomelo09
    @ThePomelo09 4 роки тому +2

    Thank you!!

  • @MohammedMutwakil
    @MohammedMutwakil 4 роки тому +1

    Thank you very much

  • @shelendrasharma9680
    @shelendrasharma9680 3 роки тому

    Hi Jakob, an amazing lecture:). I AM a big admirer of your knowledge. I have a doubt.
    why do we synchronize the below method in thread pool class as the blocking queue is already thread-safe
    ? why an explicit sync is required here?
    public synchronized void execute(Runnable task) throws Exception{
    }

    • @JakobJenkov
      @JakobJenkov  3 роки тому +1

      You are right - it should be enough to just rely on the BlockingQueue to be thread-safe. I think I just synchronized the methods to avoid having to answer the reverse question: "Why is the execute() method NOT synchronized" ? :-) .... and thank you for your kind words! I am happy my videos have helped you ! :-)

  • @azatakhunov6061
    @azatakhunov6061 3 роки тому +1

    good video!

  • @minasalah8210
    @minasalah8210 3 роки тому +1

    thank you.

  • @abenezertilahun610
    @abenezertilahun610 3 роки тому +1

    Thank you

  • @RitaTheCuteFox
    @RitaTheCuteFox 3 роки тому +2

    thanks

  • @animanaut
    @animanaut 2 роки тому +1

    i wonder if this is how in part an actor model is implemented

  • @basavaraj2065
    @basavaraj2065 4 роки тому +1

    Do we need ThreadPool when Executor service API available ? I believe Executor API are improvised version of ThreadPool

    • @JakobJenkov
      @JakobJenkov  4 роки тому

      If the ExecutorService provides all the functionality you need, then yes, use the ExecutorService, so you don't have to implement a thread pool yourself, and you don't mess up anything :-) Only if yo uneed some functionality that the ExecutorService does not provide, does it make sense to implement your own thread pool. Or - as a learning experience.

  • @prometheusli101
    @prometheusli101 3 роки тому +1

    but the (max number of task) was inoperative,if i change the for loop number i to

    • @JakobJenkov
      @JakobJenkov  3 роки тому +2

      True - in the implementation shown in the video, if you add more tasks to the thread pool than it has capacity for, the extra tasks are just ignored. You can change that implementation if you need smarter behaviour :-)

  • @druzzyaka
    @druzzyaka 3 роки тому +4

    Jacob, as always, thank you for the lesson 🙂
    I copied your code and slightly modified it to measure the execution time. Then I increased the number of tasks to 5_000_000 and ran the program with different amount of threads available in the thread pool.
    To my surprise, single threaded result is always 50% faster then multithreaded, although my cpu is dual core with 4 threads.
    Then I looked in the CPU utilization chart and found out, that even if I run the program in single thread, CPU load is distributed evenly between all 4 threads, ~90% utilization for each.
    Could you please explain such a counterintuitive behaviour?

    • @JakobJenkov
      @JakobJenkov  3 роки тому +4

      Hmm... it is possible that the 4 threads lose some time while being blocked - trying to take a task from the internal task queue in the thread pool. A single thread will not have that problem. However, if your tasks were downloading files from the Internet, I am sure you would see that the multithreaded version would perform better than the singlethreaded version! When downloading - the threads will be blocked most of the time waiting for a result from the remote server, so congestion on the internal task queue would be lower.

    • @druzzyaka
      @druzzyaka 3 роки тому +1

      @@JakobJenkov Thank you for the answer!
      Is it possible, that the task for each thread is too easy in the example? So the frequency of queries to the task queue is too high for multithreading to be effective?

  • @AlouiMohamedhabib
    @AlouiMohamedhabib 4 роки тому +1

    NIce thank you.

  • @shortsum
    @shortsum 3 роки тому

    What would the equivalent code using reentrant lock. Do we need to guard the take method as well ?

    • @JakobJenkov
      @JakobJenkov  3 роки тому

      That is for you to figure out :-) The more you learn about how concurrency works in Java, the easier it will be for you to figure out!

    • @shortsum
      @shortsum 3 роки тому

      @@JakobJenkov Thanks, i tried multiple times and finally I understood what a lock and it's condition exactly does and how to effectively use it. I was able to get it work. In my opinion modifying your tutorials with lock and condition is probably the best way to start with. Also do you know of any resources where I can try out fixing the unsynchronized code and test out my knowledge. Thanks once again.

  • @小粉红-s5z
    @小粉红-s5z 3 роки тому

    why waitUntilAllTasksFinished() needs to sleep for 1 ms if taskQueue size is > 0?

    • @JakobJenkov
      @JakobJenkov  2 роки тому +1

      It sleeps in a loop, so it keeps checking if the taskQueue size has changed - but since it may take some time for task queue size to change it does not just immediately check again. It sleeps 1 ms to give the pool threads a chance to finish more work. This is a simplified way of waiting. In a real implementation you might do it differently - using thread signaling (wait() + notify()).

  • @mok8957
    @mok8957 Рік тому

    thx for that

  • @mannysingh6618
    @mannysingh6618 3 роки тому

    ThreadPool class does not need to synchronize at method level.

    • @JakobJenkov
      @JakobJenkov  3 роки тому

      I know... but that is a tiny difference in practice, unless you have many threads submitting tasks to the same thread pool. You can keep refining most components, but this video only serves ti illustrate the core principles... which it seems you already understand since you spotted the unnecessary synchronization.

  • @aamirngr
    @aamirngr 3 роки тому

    why execute function defination is declared synchronized when only main thread calls it? there is no other thread except main thread that calls execute method

    • @JakobJenkov
      @JakobJenkov  3 роки тому +2

      In case more than one thread was to submit tasks to the same thread pool, having its execute() method be synchronized is handy.

    • @shortsum
      @shortsum 3 роки тому

      @@JakobJenkov Will it affect the synchronization , given the queue is already guarding it with lock in enqueue and dequeue methods. I tried this out and got an expected result.

  • @matimozg
    @matimozg Рік тому

    When I start main class first time I got exception and only 9 tasks done. I tried run main method many times after that but always program return without errors.

    • @JakobJenkov
      @JakobJenkov  Рік тому

      Strange... if you find out why - let me know!

    • @relax7105
      @relax7105 10 місяців тому

      @@JakobJenkov I tried to investigate it with adding sleep of 3 sec in each runnabletask that is to be executed. The last task doesnot complete in this case. because in waitUntilAllTasksFinished method you checked the taskQueue size and based on that you waited for 1 ms and exited and called stop in main thread which stops all PoolRunnablethread. but even runnable.run task was sleeping for 3sec it got call to interrrupt and that's why last task couldn't complete.

    • @relax7105
      @relax7105 10 місяців тому

      @JakobJenkov I think this can be handled by increasing the thread.sleep() time in waitUntilAllTasksFinished() method.

  • @anujcse06525
    @anujcse06525 2 роки тому

    If we put Thread.sleep(1000); below String message = Thread.currentThread().getName() + ": Task " + taskNo; there will be java.lang.InterruptedException: sleep interrupted

  • @vinit720
    @vinit720 3 роки тому

    It is not working in hibernate application

    • @JakobJenkov
      @JakobJenkov  3 роки тому

      What do you mean "it is not working... " ? You need to provide more details if anyone are to be able to help you.

    • @vinit720
      @vinit720 3 роки тому

      @@JakobJenkov Hi Jakob. Hope you would be well and doing great. My concern is that when I am running your code is running perfectly in standalone Java project main() method but when I am trying to run it inside a method in hibernate application multiple threads are not being created by thread pool. Hope u get what I trying to explain!

  • @thesoftwareengineer17
    @thesoftwareengineer17 2 роки тому

    plz share the github link for same

    • @JakobJenkov
      @JakobJenkov  Рік тому

      It's here : github.com/jjenkov/java-examples

  • @gregchen4023
    @gregchen4023 3 роки тому

    missing " " makes the code so difficult to understand, and you implemented 2 levels of "nested" runnable interface which makes the code with this mistake even harder to understand.
    I spent hours to understand the code in your text version of tutorial, till I found your video where you correct the mistake in the code. But your text version still has this mistake un-corrected.

    • @JakobJenkov
      @JakobJenkov  3 роки тому

      What missing are you talking about? That the BlockingQueue variable inside ThreadPoolRunnable is not declared as BlockingQueue ?
      You should be able to abstract from that pretty easily. The taskQueue variable is only referenced in 3 places, and one of them casts the obtained object to a Runnable.
      Also, the code in the video is the same that is copied into the article.

  • @virrao1334
    @virrao1334 3 місяці тому

    wow

  • @gregchen4023
    @gregchen4023 3 роки тому

    the implementation is wrong, if the number of tasks is greater than the size of the block queue, it does not block and the tasks that are not in the queue are abandoned.

    • @JakobJenkov
      @JakobJenkov  3 роки тому

      That is how the current ThreadPool implementation is designed to work. If you want to block until there is space in the BlockingQueue, call it's put() method instead of offer(), or change the ThreadPool.execute() method to return the value returned from BlockingQueue.offer() . Simple. Done.