{"id":56857,"date":"2023-03-15T13:08:49","date_gmt":"2023-03-15T07:38:49","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=56857"},"modified":"2023-03-17T13:02:16","modified_gmt":"2023-03-17T07:32:16","slug":"project-loom-launching-10-million-threads-part-2","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/project-loom-launching-10-million-threads-part-2\/","title":{"rendered":"Java Project Loom &#8211; Launching 10 million threads (Part 2)"},"content":{"rendered":"<p>In the <a href=\"https:\/\/www.tothenew.com\/blog\/java-project-loom-virtual-threads-part-1\/\">previous blog<\/a>, we discussed a detailed overview of Project Loom. Now it\u2019s time for some code. If you have not read about part 2 of this series, please check it out here:<\/p>\n<p>Let us see how we can create virtual threads in Java.<\/p>\n<pre class=\"zj zk zl zm wx ago agp eg gm agq agr bx\"><span id=\"3f88\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\">Thread.ofVirtual().unstarted(() -&gt; System.out.println(<span class=\"hljs-string\">\"Thread is not started\"<\/span>));<\/span><\/pre>\n<pre class=\"vx ago agp eg gm agq agr bx\"><span id=\"914c\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\"> Thread.ofVirtual().start(() -&gt; System.out.println(<span class=\"hljs-string\">\"Thread is not started\"<\/span>));<\/span><\/pre>\n<p id=\"1583\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">In the first example, we created a virtual thread but in unstarted mode. In second example, we created a virtual thread in started mode. Simple stuff. There\u2019s nothing fancy about it.<\/p>\n<p id=\"8d7b\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">Now let\u2019s run the below program and see the output<\/p>\n<pre class=\"zj zk zl zm wx ago agp eg gm agq agr bx\"><span id=\"0247\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title.function\">main<\/span><span class=\"hljs-params\">(String[] args)<\/span> <span class=\"hljs-keyword\">throws<\/span> InterruptedException {\r\n        <span class=\"hljs-type\">var<\/span> <span class=\"hljs-variable\">thread<\/span> <span class=\"hljs-operator\">=<\/span> Thread.ofVirtual().unstarted(() -&gt; System.out.println(Thread.currentThread()));\r\n        thread.start();\r\n        thread.join();\r\n    }<\/span><\/pre>\n<p id=\"ee75\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">Output<\/p>\n<pre class=\"zj zk zl zm wx ago agp eg gm agq agr bx\"><span id=\"6026\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\">VirtualThread[<span class=\"hljs-comment\">#22]\/runnable<span class=\"hljs-doctag\">@ForkJoinPool<\/span>-1-worker-1<\/span><\/span><\/pre>\n<p id=\"44bd\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">We can see that\u00a0<strong class=\"rf mr\"><em class=\"zv\">VirtualThread [#22]<\/em><\/strong>\u00a0has been created and is running the task of printing the line. Also, we can see\u00a0<strong class=\"rf mr\"><em class=\"zv\">ForkJoinPool-1-worker-1\u00a0<\/em>l<\/strong>iteral in the output. This means that our\u00a0<strong class=\"rf mr\"><em class=\"zv\">VirtualThread[#22]<\/em><\/strong>\u00a0is running on top of a platform thread with the name\u00a0<strong class=\"rf mr\"><em class=\"zv\">ForkJoinPool-1-worker-1.\u00a0<\/em><\/strong>Clearly, virtual threads are running on top of the ForkJoinPool.<strong class=\"rf mr\"><em class=\"zv\">\u00a0<\/em><\/strong>Is it the same common ForkJoinPool that we use to submit the task? Let\u2019s check this out by running the following program:<\/p>\n<pre class=\"zj zk zl zm wx ago agp eg gm agq agr bx\"><span id=\"f7e1\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span>(<span class=\"hljs-params\">String[] args<\/span>) throws InterruptedException<\/span> {\r\n    ForkJoinPool.commonPool().submit(\r\n          () -&gt; System.<span class=\"hljs-keyword\">out<\/span>.println(Thread.currentThread())\r\n        );\r\n}<\/span><\/pre>\n<p id=\"d11a\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">Output<\/p>\n<pre class=\"zj zk zl zm wx ago agp eg gm agq agr bx\"><span id=\"2451\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\">Thread[<span class=\"hljs-comment\">#22,ForkJoinPool.commonPool-worker-1,5,main]<\/span><\/span><\/pre>\n<p id=\"e872\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">Clearly,\u00a0<strong class=\"rf mr\">ForkJoinPool-1-worker-1<\/strong>\u00a0and\u00a0<strong class=\"rf mr\">ForkJoinPool.commonPool-worker-1<\/strong>\u00a0are not same. Virtual threads are running on fork join pool which is different from common fork join pool introduced in java 7.<\/p>\n<p id=\"23d3\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">Let\u2019s see one more interesting thing about virtual thread by running the following program<\/p>\n<pre class=\"zj zk zl zm wx ago agp eg gm agq agr bx\"><span id=\"ee4f\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\"> <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title.function\">main<\/span><span class=\"hljs-params\">(String[] args)<\/span> <span class=\"hljs-keyword\">throws<\/span> InterruptedException {\r\n    Thread.ofVirtual().start(() -&gt; System.out.println(<span class=\"hljs-string\">\"Thread is not started\"<\/span>));\r\n    <span class=\"hljs-type\">var<\/span> <span class=\"hljs-variable\">threads<\/span> <span class=\"hljs-operator\">=<\/span> IntStream.range(<span class=\"hljs-number\">0<\/span>,<span class=\"hljs-number\">10<\/span>)\r\n      .mapToObj(\r\n          index -&gt; Thread.ofVirtual().unstarted(() -&gt; {\r\n              <span class=\"hljs-keyword\">if<\/span>(index == <span class=\"hljs-number\">0<\/span>){\r\n                  System.out.println(Thread.currentThread());\r\n              }\r\n              <span class=\"hljs-keyword\">try<\/span> {\r\n                  Thread.sleep(<span class=\"hljs-number\">10<\/span>);\r\n              } <span class=\"hljs-keyword\">catch<\/span> (InterruptedException e) {\r\n                  <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-title.class\">RuntimeException<\/span>(e);\r\n              }\r\n              <span class=\"hljs-keyword\">if<\/span>(index == <span class=\"hljs-number\">0<\/span>){\r\n                  System.out.println(Thread.currentThread());\r\n              }\r\n          })).toList();\r\n    threads.forEach(Thread::start);\r\n    <span class=\"hljs-keyword\">for<\/span>(Thread thread : threads){\r\n        thread.join();\r\n    }\r\n  }<\/span><\/pre>\n<p id=\"8aeb\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">We are creating 10 virtual threads and letting the 0th thread print its thread name. We allow it to sleep for 10 milliseconds, and then we are again trying to print the 0th thread to print its name. Let\u2019s see the result.<\/p>\n<pre class=\"zj zk zl zm wx ago agp eg gm agq agr bx\"><span id=\"61ec\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\">VirtualThread[<span class=\"hljs-comment\">#25]\/runnable<span class=\"hljs-doctag\">@ForkJoinPool<\/span>-1-worker-2<\/span>\r\nVirtualThread[<span class=\"hljs-comment\">#25]\/runnable<span class=\"hljs-doctag\">@ForkJoinPool<\/span>-1-worker-10<\/span><\/span><\/pre>\n<p id=\"e859\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">We can see that\u00a0<strong class=\"rf mr\"><em class=\"zv\">Virtual Thread #25<\/em><\/strong>\u00a0first ran on platform thread\u00a0<strong class=\"rf mr\">ForkJoinPool-1-worker-2<\/strong>. It\u2019s been asleep for 10 milliseconds. When it wakes up, it is pinned to another platform thread with the name\u00a0<strong class=\"rf mr\"><em class=\"zv\">runnable@ForkJoinPool-1-worker-10<\/em><\/strong>. So clearly, we can see that whenever the virtual thread is blocked, it releases the platform thread, and its stack is moved to the heap memory. The platform thread can now be pinned to another virtual thread to carry out its task. When the blocking operation is finished, the virtual thread will be pinned to any free platform thread and will mount its stack on that platform thread.<\/p>\n<p id=\"891f\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">This is new in Java, and it\u2019s great. Blocking a thread is cheap. Cost is only un-mounting the call-stack from platform thread and storing in heap and vice versa.<\/p>\n<p id=\"501c\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">Now it\u2019s the time to launch threads. Lets launch 100 of threads with the below program.<\/p>\n<pre class=\"zj zk zl zm wx ago agp eg gm agq agr bx\"><span id=\"bbd1\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\"> <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title.function\">main<\/span><span class=\"hljs-params\">(String[] args)<\/span> <span class=\"hljs-keyword\">throws<\/span> InterruptedException {\r\n     <span class=\"hljs-type\">var<\/span> <span class=\"hljs-variable\">list<\/span> <span class=\"hljs-operator\">=<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-title.class\">HashSet<\/span>&lt;String&gt;();\r\n     <span class=\"hljs-type\">var<\/span> <span class=\"hljs-variable\">millis<\/span> <span class=\"hljs-operator\">=<\/span> System.currentTimeMillis();\r\n     <span class=\"hljs-type\">var<\/span> <span class=\"hljs-variable\">vthreadcounts<\/span> <span class=\"hljs-operator\">=<\/span> <span class=\"hljs-number\">100<\/span>;\r\n     <span class=\"hljs-type\">var<\/span> <span class=\"hljs-variable\">threads<\/span> <span class=\"hljs-operator\">=<\/span> IntStream.range(<span class=\"hljs-number\">0<\/span>,vthreadcounts)\r\n        .mapToObj(\r\n          index -&gt; Thread.ofVirtual().unstarted(() -&gt; {\r\n              <span class=\"hljs-type\">var<\/span> <span class=\"hljs-variable\">abc<\/span> <span class=\"hljs-operator\">=<\/span>  <span class=\"hljs-string\">\"VirtualThread[#22]\/runnable@ForkJoinPool-1-worker-1\"<\/span>.contains(<span class=\"hljs-string\">\"runnable@ForkJoinPool-1\"<\/span>);\r\n              <span class=\"hljs-type\">var<\/span> <span class=\"hljs-variable\">threadName<\/span> <span class=\"hljs-operator\">=<\/span> Thread.currentThread().toString();\r\n             <span class=\"hljs-keyword\">if<\/span>(abc) list.add(threadName.substring(threadName.indexOf(<span class=\"hljs-string\">\"\/\"<\/span>)));\r\n          })).toList();\r\n\r\n      threads.forEach(Thread::start);\r\n      <span class=\"hljs-keyword\">for<\/span>(Thread thread : threads){\r\n          thread.join();\r\n      }\r\n      <span class=\"hljs-type\">var<\/span> <span class=\"hljs-variable\">millis1<\/span> <span class=\"hljs-operator\">=<\/span> System.currentTimeMillis();\r\n      System.out.println(<span class=\"hljs-string\">\"millis used to launch \"<\/span> + vthreadcounts + <span class=\"hljs-string\">\"vthreads:\"<\/span> + (millis1 - millis) + <span class=\"hljs-string\">\"ms\"<\/span>);\r\n      System.out.println(<span class=\"hljs-string\">\"number of platform thread used:\"<\/span> + list.size());\r\n   }<\/span><\/pre>\n<p id=\"6386\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">We are using some logic to calculate the number of platform threads required to run 100 virtual threads. Also, we wrote logic to calculate the time it takes in milliseconds to execute it. Let\u2019s see the output of this program.<\/p>\n<pre class=\"zj zk zl zm wx ago agp eg gm agq agr bx\"><span id=\"bef9\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\">millis used to launch <span class=\"hljs-number\">100<\/span>vthreads:<span class=\"hljs-number\">23<\/span>ms\r\nnumber of platform thread used:<span class=\"hljs-number\">7<\/span><\/span><\/pre>\n<p id=\"d255\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">It took 23 milliseconds and have used 7 platform thread.<\/p>\n<p id=\"f43b\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">Let\u2019s us put more pressure on the program by changing the vthreadcounts to 1000. Let\u2019s see the output now.<\/p>\n<pre class=\"zj zk zl zm wx ago agp eg gm agq agr bx\"><span id=\"39e3\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\">millis used to launch <span class=\"hljs-number\">1000<\/span>vthreads:<span class=\"hljs-number\">23<\/span>ms\r\nnumber of platform thread used:<span class=\"hljs-number\">10<\/span><\/span><\/pre>\n<p id=\"cf7e\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">Nothing, its still took 23 milliseconds and platform thread used is 10 in this case. Let us put more pressure on it and run for 10,000 threads and see the output.<\/p>\n<pre class=\"zj zk zl zm wx ago agp eg gm agq agr bx\"><span id=\"9e2e\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\">millis used to launch <span class=\"hljs-number\">10000<\/span>vthreads:<span class=\"hljs-number\">57<\/span>ms\r\nnumber of platform thread used:<span class=\"hljs-number\">10<\/span><\/span><\/pre>\n<p id=\"8737\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">It took now 57 milliseconds and platform thread used is 10. Quite impressive. Let us put some more pressure on it and run for 100,000 threads and see the result.<\/p>\n<pre class=\"zj zk zl zm wx ago agp eg gm agq agr bx\"><span id=\"02b1\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\">millis used to launch <span class=\"hljs-number\">100000<\/span>vthreads:<span class=\"hljs-number\">246<\/span>ms\r\nnumber of platform thread used:<span class=\"hljs-number\">10<\/span><\/span><\/pre>\n<p id=\"ed31\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">Still only 246 milliseconds and 10 platform threads. Still under 1 second. Time to put some serious pressure and look for 1000,000 (1 million) threads.<\/p>\n<pre class=\"zj zk zl zm wx ago agp eg gm agq agr bx\"><span id=\"ed72\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\">millis used to launch <span class=\"hljs-number\">1000000<\/span>vthreads:<span class=\"hljs-number\">1286<\/span>ms\r\nnumber of platform thread used:<span class=\"hljs-number\">10<\/span><\/span><\/pre>\n<p id=\"e57e\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">Now, it took 1286 milliseconds, just little more that 1 second and used 10 platform thread.<\/p>\n<p id=\"1af8\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">Now, we are in finale and will run for 10 million threads i.e 10,000,000 threads. Have you ever done that. This is insane amount of numbers.<\/p>\n<pre class=\"zj zk zl zm wx ago agp eg gm agq agr bx\"><span id=\"0cc9\" class=\"ags agt xr agp b bv agu agv y agw agx\" data-selectable-paragraph=\"\">millis used to launch <span class=\"hljs-number\">10000000<\/span>vthreads:<span class=\"hljs-number\">8762<\/span>ms\r\nnumber of platform thread used:<span class=\"hljs-number\">10<\/span><\/span><\/pre>\n<p id=\"3f73\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">And we are able to run our 10 million threads in just less than 9 seconds.<\/p>\n<p id=\"295c\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">Even though we are not doing much in our threads but still running 10 million threads in less than 9 seconds is no mean feat.<\/p>\n<p id=\"387d\" class=\"pw-post-body-paragraph yn yo xr rf b yp yq uq yr ys yt ut yu yv yw yx yy yz za zb zc zd ze zf zg zh ny bx\" data-selectable-paragraph=\"\">Project loom guys are doing great job. In coming parts we will be taking a look into StructuredTaskScope which is quite amazing feature of this project Loom.<\/p>\n<p data-selectable-paragraph=\"\">This blog was originally published in Medium, read <a href=\"https:\/\/medium.com\/@anil.java.story\/project-loom-launching-10-million-threads-part-2-e0b2eb716b8b\">here<\/a>.<\/p>\n<div class=\"ap-custom-wrapper\"><\/div><!--ap-custom-wrapper-->","protected":false},"excerpt":{"rendered":"<p>In the previous blog, we discussed a detailed overview of Project Loom. Now it\u2019s time for some code. If you have not read about part 2 of this series, please check it out here: Let us see how we can create virtual threads in Java. Thread.ofVirtual().unstarted(() -&gt; System.out.println(&#8220;Thread is not started&#8221;)); Thread.ofVirtual().start(() -&gt; System.out.println(&#8220;Thread is [&hellip;]<\/p>\n","protected":false},"author":1520,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":3},"categories":[446],"tags":[5134,5133],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/56857"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/1520"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=56857"}],"version-history":[{"count":6,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/56857\/revisions"}],"predecessor-version":[{"id":56902,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/56857\/revisions\/56902"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=56857"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=56857"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=56857"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}