<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://josephmate.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://josephmate.github.io/" rel="alternate" type="text/html" /><updated>2026-01-22T10:34:44-05:00</updated><id>https://josephmate.github.io/feed.xml</id><title type="html">Joseph Mate</title><author><name>Joseph Mate</name></author><entry><title type="html">Ghost in the Wi-Fi</title><link href="https://josephmate.github.io/2026-01-20-ghost-in-the-wifi/" rel="alternate" type="text/html" title="Ghost in the Wi-Fi" /><published>2026-01-20T22:44:00-05:00</published><updated>2026-01-20T22:44:00-05:00</updated><id>https://josephmate.github.io/ghost-in-the-wifi</id><content type="html" xml:base="https://josephmate.github.io/2026-01-20-ghost-in-the-wifi/"><![CDATA[<p>Last time I checked the clock, it was 11:00am and right now I have no idea because I’m in the <a href="https://en.wikipedia.org/wiki/Flow_(psychology)">flow state</a>.
The bug had no chance.
I’m now wrapping up the report in my pull request.
An Outlook popup breaks through my concentration, reminding me of a meeting in 5 minutes!!!
I hop onto teams but it’s not connecting.
Oh no!
This is the worst time to lose my connection.
I have no time to debug, not even enough time to restart my modem.
That’ll have to wait for another time.
I turn on my mobile hotspot and connect to that.
I make it late to my meeting, but the meeting hasn’t started yet because I’m not last to arrive.
I let out a huge sigh of relief.
During the entire meeting, something is nagging away at me preventing me from focusing on my meeting.
My phone’s internet through wifi looked ok before I had to disconnect for the mobile hotspot.</p>

<h1 id="first-clue">First Clue</h1>

<p>With my meeting, over I try to recover the internet on my laptop.
First thing I notice is as I switch off my mobile hotspot, my phone has internet through wifi but my laptop still does not.
That’s fishy.
It’s likely an issue with my laptop.
I do the normal troubleshooting steps:</p>
<ol>
  <li>reset computer</li>
  <li>reset modem</li>
  <li>on laptop forget wifi</li>
  <li>on modem, forget laptop</li>
</ol>

<p>It wasn’t until step 4 that my laptop regained internet.
I was confused, but relieved that I could get back to work.</p>

<p>30 minutes later, and my internet connection was out again.
I didn’t have time to keep messing with my wifi,
so I hopped back on my mobile hotspot to avoid anymore interruptions and get back into the flow.
Fortunately, I didn’t have any meetings for the rest of the day so I was able to merge the bugfix.</p>

<h1 id="joseph-mate-a-note-to-the-reader">Joseph Mate (a note to the reader)</h1>

<p>Some readers at this point might already know what the issue is just from the facts above and wondering why I’m even writing about it.
My only background in networking is a networking course 14 years ago.
I’ve never done desk support, and all of my debugging has been in software stack.
The closest I got to diagnosing these kinds of issues was a lab from that course 14 years ago, where we setup LAN routing and a DHCP server.
So this article is for those software developers that haven’t peered below the software stack
and also to share how excited I was to solve it myself!</p>

<h1 id="second-clue">Second Clue</h1>

<p>With the day over, and nothing on my plate, it was time to get serious.
What was going on?
Only my laptop had the issue.
The wifi modem had to forget my laptop before I could reconnect.
Just before forgetting the modem on my laptop, I noticed something strange.
My laptop’s local IP address was 192.168.0.3!
Because I always go to 192.168.2.1 to reset my modem, I knew that my IP address should have been in the 192.168.2.0/24 subnet.
How did I get this unexpected IP address?</p>

<h1 id="dchp">DCHP</h1>

<p>I googled for various permutations of the fact above, I stumbled upon this stackoverflow article: <a href="https://superuser.com/questions/1858131/why-is-the-ip-address-in-network-macbook-setting-is-different-than-the-ip-in-t/1858168">Why is the IP address in network (MacBook setting) is different than the IP in the router’s config page?</a></p>

<p><a href="https://superuser.com/a/1858168/293310">The top answer</a> says to assign a static IP to fix the issue but does not explain how or why the laptop was given a new IP address.</p>

<p>The comments provided more valuable theories:</p>

<blockquote>
  <p><a href="https://superuser.com/questions/1858131/why-is-the-ip-address-in-network-macbook-setting-is-different-than-the-ip-in-t#comment2947034_1858131">Your MacBook and your phone are not connected to the same network.</a></p>
</blockquote>

<p>This is one level deeper and explains why internet connectivity was lost but not why we were given an new IP address.</p>

<blockquote>
  <p><a href="https://superuser.com/questions/1858131/why-is-the-ip-address-in-network-macbook-setting-is-different-than-the-ip-in-t#comment2947091_1858131">You probably have two devices acting as NAT gateways and DHCP servers on your network. </a></p>
</blockquote>

<p>When a device connects to a local network, by default it broadcasts a message asking for an IP address. 
This was what I initially thought too and quickly rejected because I’m not running a second DHCP server.
This comment made me reconcider the second DHCP theory
so I enumerated all the devices on my network to double check:</p>

<pre><code class="language-mermaid">flowchart TD
  ISP@{            icon: "mdi:web",               form: "square", label: "ISP" }
  ModemWifiCombo@{ icon: "mdi:router-wireless",   form: "square", label: "Modem Wifi Router Combo" }
  Laptop@{         icon: "mdi:laptop",            form: "square", label: "2 Laptops" }
  TV@{             icon: "mdi:television",        form: "square", label: "TV" }
  SmartPhone@{     icon: "mdi:cellphone",         form: "square", label: "2 Smart Phones" }
  PC@{             icon: "mdi:server",            form: "square", label: "PC" }
  SmartLight@{     icon: "mdi:lightbulb-outline", form: "square", label: "6 Smart Lights" }
  SecurityCamera@{ icon: "mdi:webcam",            form: "square", label: "5 Security Cameras" }

  ModemWifiCombo --&gt; ISP
  Laptop--&gt; ModemWifiCombo
  TV --&gt; ModemWifiCombo
  SmartPhone --&gt; ModemWifiCombo
  SmartLight --&gt; ModemWifiCombo
  SecurityCamera --&gt; ModemWifiCombo
</code></pre>

<p>I connect to the Internet through a modem provided by the ISP that also has a wifi router in it.
All my devices talk through wifi on either 2.4 or 5 GHz.
None of the devices should be running a DHCP server.
We had a ghost in the wifi!
The DHCP server wasn’t the root cause.</p>

<h1 id="wireshark">Wireshark</h1>

<p>So I installed <a href="https://www.wireshark.org/">Wireshark</a> and starting recording everything I was receiving from the network. Half an hour later I got:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>56711   1106.460911 0.0.0.0 255.255.255.255 DHCP    342 DHCP Discover - Transaction ID 0xa94a124d
56713   1106.472187 192.168.2.1 192.168.2.26    DHCP    342 DHCP Offer    - Transaction ID 0xa94a124d
56715   1106.550081 192.168.0.1 255.255.255.255 DHCP    342 DHCP Offer    - Transaction ID 0xa94a124d
</code></pre></div></div>

<p>For some reason there is a DHCP Discover and <strong>TWO</strong> things respond back. Where did 192.168.0.1 come from?</p>

<p>The message from 192.168.2.1 is (note: I changed all the MAC addresses because I did not feel comfortable giving mine away):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Ethernet II, Src: SagemcomBroa_00:00:00 (80:20:da:00:00:00), Dst: Apple_00:00:00 (84:38:35:00:00:00)
</code></pre></div></div>

<p>The src is the mac address of my modem which I confirmed by logging into the management UI and finding 80:20:DA:00:00:00 as the WAN Mac address.</p>

<p>The message from 192.168.0.1 is:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Ethernet II, Src: AltoBeam_00:00:00 (38:be:ab:00:00:00), Dst: Broadcast (ff:ff:ff:ff:ff:ff)
</code></pre></div></div>
<p>I have no idea what AltoBeam_00:00:00 is! Not only that, it’s not specifically sending it to me (Apple_00:00:00), it’s broadcasting it.</p>

<p>I have given up on finding AltoBeam_00:00:00. I suspect it’s my broken security camera that lost connection to the network. For now to workaround this I set the IP manually so I can keep debugging with a stable internet connection.</p>

<p>System Settings -&gt; Wifi -&gt; Details - TCP/IP:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    Configure IPv4: Manually
    IP address: 192.168.2.26 (this is the one the router was reporting)
    Subnet mask: 255.255.255.0
    Router: 192.168.2.1 (this is the one my wifi router uses)
</code></pre></div></div>

<p>Later, I consulted the Smart Home management app on my phone and it says that AltoBeam_00:00:00 is my outdoor security camera!
This is one of the cameras that is working though!
It’s not the broken one.
I’m able to view the live feed without issue.
It should not be running a DHCP server
and I’m not sure how stop it other than throw the camera out.</p>

<p>Now that I know the root cause, I can see multiple people reporting it:</p>
<ul>
  <li><a href="https://forum.openwrt.org/t/some-device-doesnt-receive-default-gateway/184084/4">Some Device doesn’t Receive Default Gateway</a></li>
  <li><a href="https://www.reddit.com/r/SecurityCamera/comments/1729s6v/problem_xiaomi_aw300_cam_disconnects_wifi/">Problem: Xiaomi AW300 cam disconnects Wi-Fi</a></li>
  <li><a href="https://www.reddit.com/r/Network/comments/18is4f6/multiple_xiaomi_smart_cameras_causing_laptop_and/">Multiple Xiaomi Smart cameras causing laptop and Mobile phone to disconnect from Wifi router</a></li>
</ul>

<h1 id="solution">Solution</h1>

<p>Unfortunately, I cannot simply stop using the security camera.
I spent so much time mounting it and wiring it, so I was way too lazy to buy and install another one.
So I followed the advice from the <a href="https://superuser.com/a/1858168/293310">top answer in the stack overflow thread</a> and continued to assign a static IP to my laptop.
The static IP workaround became a permanant fix.
The problem never came back for my laptop.</p>

<h1 id="why-does-my-security-camera-run-a-dhcp-server">Why does my security camera run a DHCP server?</h1>

<p>One of the approaches smart devices like this security camera, smart lights and others use is to ask you to connect to their temporary wifi network in order for you to send your wifi password to the device.
Some examples:</p>
<ul>
  <li><a href="https://www.tp-link.com/us/support/faq/946/">Kasa smart plugin install guide</a></li>
  <li><a href="https://www.tp-link.com/us/support/faq/2710/">TP Link camera</a></li>
</ul>

<p>Unfortunately for me, the DHCP server was running outside of this device setup window.</p>

<p>As an example, from <a href="https://github.com/paramaggarwal/mi-camera">Xiaomi Mi 360° 1080p Full HD WiFi Smart Security Camera Recovery Image</a>,
if you extract it using <a href="https://www.7-zip.org/">7-Zip</a>,
you will find a <a href="https://www.linuxjournal.com/content/embracing-future-transition-sysvinit-systemd-linux">legacy SysVinit</a> script located at <code class="language-plaintext highlighter-rouge">/etc/init.d/S41wifi</code></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh</span>
<span class="c">#</span>
<span class="c"># Start the wifi...</span>
<span class="c">#</span>

<span class="k">case</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="k">in
  </span>start<span class="p">)</span>

        <span class="nb">echo</span> <span class="s2">"Starting wifi ......"</span>
        /mnt/data/bin/wifi_start.sh &amp;
                <span class="p">;;</span>
  stop<span class="p">)</span>
        <span class="nb">printf</span> <span class="s2">"Stopping wifi..."</span>
        /usr/bin/killall wpa_supplicant hostapd dhcpd
        /sbin/ifconfig wlan0 down
        /sbin/modprobe <span class="nt">-r</span> mt7601Usta.ko
        <span class="p">;;</span>
  restart|reload<span class="p">)</span>
        <span class="s2">"</span><span class="nv">$0</span><span class="s2">"</span> stop
        <span class="s2">"</span><span class="nv">$0</span><span class="s2">"</span> start
        <span class="p">;;</span>
  <span class="k">*</span><span class="p">)</span>
        <span class="nb">echo</span> <span class="s2">"Usage: </span><span class="nv">$0</span><span class="s2"> {start|stop|restart}"</span>
        <span class="nb">exit </span>1
<span class="k">esac

</span><span class="nb">exit</span> <span class="nv">$?</span>
</code></pre></div></div>

<p>The link provided seems like an incomplete copy of the firmware because
I do not have access to <code class="language-plaintext highlighter-rouge">/mnt/data/bin/wifi_start.sh</code>.
I suspect that’s where the <a href="https://man.openbsd.org/dhcpd.8">dhcpd</a> is started.</p>

<h1 id="open-questions">Open Questions</h1>

<p>I’m glad to have a stable internet connection again,
but I’m only partially statisfied with the outcome because these answers just bring more questions than what I started with.
It also leaves me with a humble understanding of the limitation of my skills in networking and hardware.</p>

<ol>
  <li>Why didn’t any of my other devices like my phone fall victim to the double DHCP server? Is it limited to some OSes?</li>
  <li>Shouldn’t my laptop have had a stickier commitment to the DHCP server it was already using if it was still working?</li>
  <li>Why does my security camera run a DHCP server outside of the setup process? A bug? I wish I could see that particular device’s source code.</li>
</ol>]]></content><author><name>Joseph Mate</name></author><category term="Networking" /><category term="Wireshark" /><category term="Internet" /><category term="Debugging" /><summary type="html"><![CDATA[Last time I checked the clock, it was 11:00am and right now I have no idea because I’m in the flow state. The bug had no chance. I’m now wrapping up the report in my pull request. An Outlook popup breaks through my concentration, reminding me of a meeting in 5 minutes!!! I hop onto teams but it’s not connecting. Oh no! This is the worst time to lose my connection. I have no time to debug, not even enough time to restart my modem. That’ll have to wait for another time. I turn on my mobile hotspot and connect to that. I make it late to my meeting, but the meeting hasn’t started yet because I’m not last to arrive. I let out a huge sigh of relief. During the entire meeting, something is nagging away at me preventing me from focusing on my meeting. My phone’s internet through wifi looked ok before I had to disconnect for the mobile hotspot.]]></summary></entry><entry><title type="html">3,200% CPU Utilization</title><link href="https://josephmate.github.io/2025-02-26-3200p-cpu-util/" rel="alternate" type="text/html" title="3,200% CPU Utilization" /><published>2025-02-26T08:30:00-05:00</published><updated>2025-02-26T08:30:00-05:00</updated><id>https://josephmate.github.io/3200p-cpu-util</id><content type="html" xml:base="https://josephmate.github.io/2025-02-26-3200p-cpu-util/"><![CDATA[<p>A while back my machine was so messed up that I could barely ssh onto it.
3,200% CPU utilization - all 32 cores on the host were fully utilized!
<a href="https://josephmate.github.io/2021-10-03-my-bug-used-up-100cpu-or-did-it/">Compare that to my last bug where it only used 1 core, 100%</a></p>

<p>Fortunately, it was using Java 17 runtime which had thread dumps with CPU time!
Sorting by CPU time brought a bunch of threads that looked similar to this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"Thread-0" #22 [14700] prio=5 os_prio=0 cpu=10359.38ms elapsed=11.49s tid=0x000001cdc35aaf60 nid=14700 runnable  [0x00000047cfffe000]
   java.lang.Thread.State: RUNNABLE
	at java.util.TreeMap.put(java.base@17.0.1/TreeMap.java:826)
	at java.util.TreeMap.put(java.base@17.0.1/TreeMap.java:534)
	at BusinessLogic.someFunction(BusinessLogic.java:29)
    ...
</code></pre></div></div>

<p>I make a quick conclusion about this and thought to look at BusinessLogic:29 based
on the stack trace and it looked like this:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">someFunction</span><span class="o">(</span><span class="nc">SomeType</span> <span class="n">relatedObject</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">SomeOtherType</span><span class="o">&gt;</span> <span class="n">unrelatedObjects</span><span class="o">)</span> <span class="o">{</span>
  <span class="o">...</span>
  <span class="k">for</span> <span class="o">(</span><span class="nc">SomeOtherType</span> <span class="n">unrelatedObject</span> <span class="o">:</span> <span class="n">unrelatedObjects</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">treeMap</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">relatedObject</span><span class="o">.</span><span class="na">a</span><span class="o">(),</span> <span class="n">relatedObject</span><span class="o">.</span><span class="na">b</span><span class="o">());</span> <span class="c1">// line 29</span>
  <span class="o">}</span>
  <span class="o">...</span>
<span class="o">}</span>
</code></pre></div></div>

<p>That code is odd.
Notice we’re iterating over <code class="language-plaintext highlighter-rouge">unrelatedObject</code>, but the body of the loop only used <code class="language-plaintext highlighter-rouge">relatedObject</code>.
The code can be reduced to simply:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">someFunction</span><span class="o">(</span><span class="nc">SomeType</span> <span class="n">relatedObject</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">SomeOtherType</span><span class="o">&gt;</span> <span class="n">unrelatedObjects</span><span class="o">)</span> <span class="o">{</span>
  <span class="o">...</span>
  <span class="n">treeMap</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">relatedObject</span><span class="o">.</span><span class="na">a</span><span class="o">(),</span> <span class="n">relatedObject</span><span class="o">.</span><span class="na">b</span><span class="o">());</span>
  <span class="o">...</span>
  <span class="c1">// unrelatedObjects is used later on in the function so the parameter cannot be removed</span>
<span class="o">}</span>
</code></pre></div></div>

<p>There must have been some refactoring in the area and unrelatedObject wasn’t used anymore. 
I prepared my unit test and ran the test before and after the fix.
I tried <code class="language-plaintext highlighter-rouge">treeMap</code> and <code class="language-plaintext highlighter-rouge">unrelatedObjects</code> with 1,000,000 entries, well exceeding what the application ever saw and was not able to reproduce the problem.
Assuming unrelatedObjects is size N and treeMap is size M, the complexity is O(N lg(M)).
So it makes sense that I was unable to reproduce the problem.
<a href="https://josephmate.github.io/PowersOf2/">You wouldn’t really see one minute of execution time until 100 million to 1 billion entries.</a>.</p>

<p>It must be something else.
I was certain treeMap and unrelatedObjects never exceed 1,000 entries.
It’s not even close enough to cause an issue with an O(N lg(M)) algorithm.</p>

<p>I wasn’t very familiar with the class so I started to look around,
focusing on <code class="language-plaintext highlighter-rouge">treeMap</code> and <code class="language-plaintext highlighter-rouge">unrelatedObjects</code> to see if my assumption that they
never exceed 1,000 holds. Could they be in the millions or even billions?</p>

<p>Then I noticed the definition of the TreeMap as :</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// The field wasn't actually named treeMap.</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="nc">Map</span><span class="o">&lt;</span><span class="no">K</span><span class="o">,</span><span class="no">V</span><span class="o">&gt;</span> <span class="n">treeMap</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TreeMap</span><span class="o">&lt;&gt;();</span>
</code></pre></div></div>

<p>That’s scary.
There were multiple threads accessing the TreeMap, and it was unguarded.
At this point, I had an aha moment.
Could an unguarded TreeMap cause 3,200% utilization?</p>

<h1 id="experiment">Experiment</h1>

<p>I put together a simple experiment to try to reproduce the problem.
I created a bunch of threads randomly updating a shared TreeMap.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">numThreads</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
    <span class="n">threads</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="k">new</span> <span class="nc">Thread</span><span class="o">(()</span> <span class="o">-&gt;</span> <span class="o">{</span>
        <span class="nc">Random</span> <span class="n">random</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Random</span><span class="o">();</span>
        <span class="k">for</span><span class="o">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">numUpdates</span><span class="o">;</span> <span class="n">j</span><span class="o">++)</span> <span class="o">{</span>
            <span class="k">try</span> <span class="o">{</span>
                <span class="n">treeMap</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">(</span><span class="mi">1000</span><span class="o">),</span> <span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">(</span><span class="mi">1000</span><span class="o">));</span>
            <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">NullPointerException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
                <span class="c1">// let it keep going so we can reproduce the issue.</span>
            <span class="o">}</span>
        <span class="o">}</span>
    <span class="o">}));</span>
<span class="o">}</span>
</code></pre></div></div>
<details>
  <summary>Click to see complete source of SimpleRepro.java</summary>

  <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">java.util.*</span><span class="o">;</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">SimpleRepro</span> <span class="o">{</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span> <span class="o">{</span>

        <span class="kd">final</span> <span class="kt">int</span> <span class="n">numThreads</span><span class="o">;</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">args</span><span class="o">.</span><span class="na">length</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">numThreads</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">args</span><span class="o">[</span><span class="mi">0</span><span class="o">]);</span>
        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
            <span class="n">numThreads</span> <span class="o">=</span> <span class="mi">5</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="kd">final</span> <span class="kt">int</span> <span class="n">numUpdates</span><span class="o">;</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">args</span><span class="o">.</span><span class="na">length</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">numUpdates</span> <span class="o">=</span>  <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">args</span><span class="o">[</span><span class="mi">1</span><span class="o">]);</span>
        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
            <span class="n">numUpdates</span> <span class="o">=</span> <span class="mi">1000</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="kd">final</span> <span class="nc">TreeMap</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">treeMap</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TreeMap</span><span class="o">&lt;&gt;();</span>

        <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Thread</span><span class="o">&gt;</span> <span class="n">threads</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">numThreads</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
            <span class="n">threads</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="k">new</span> <span class="nc">Thread</span><span class="o">(()</span> <span class="o">-&gt;</span> <span class="o">{</span>
                <span class="nc">Random</span> <span class="n">random</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Random</span><span class="o">();</span>
                <span class="k">for</span><span class="o">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">numUpdates</span><span class="o">;</span> <span class="n">j</span><span class="o">++)</span> <span class="o">{</span>
                    <span class="k">try</span> <span class="o">{</span>
                        <span class="n">treeMap</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">(</span><span class="mi">1000</span><span class="o">),</span> <span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">(</span><span class="mi">1000</span><span class="o">));</span>
                    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">NullPointerException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
                        <span class="c1">// let it keep going so we can reproduce the issue.</span>
                    <span class="o">}</span>
                <span class="o">}</span>
            <span class="o">}));</span>
        <span class="o">}</span>

        <span class="k">for</span> <span class="o">(</span><span class="nc">Thread</span> <span class="n">thread</span> <span class="o">:</span> <span class="n">threads</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">thread</span><span class="o">.</span><span class="na">start</span><span class="o">();</span>
        <span class="o">}</span>

        <span class="k">for</span> <span class="o">(</span><span class="nc">Thread</span> <span class="n">thread</span> <span class="o">:</span> <span class="n">threads</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">thread</span><span class="o">.</span><span class="na">join</span><span class="o">();</span>
        <span class="o">}</span>

    <span class="o">}</span>

<span class="o">}</span>
</code></pre></div>  </div>

  <p>Complete project available at <a href="https://github.com/josephmate/java-by-experiments/blob/main/tree_map_corruption/java/src/main/java/SimpleRepro.java">SimpleRepro.java</a></p>
</details>

<p>That try catch was key.
If no try catch, I wasn’t able to reproduce the problem.
Some threads would crash with the above output:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Exception in thread "Thread-0" java.lang.NullPointerException: Cannot read field "right" because "l" is null
        at java.base/java.util.TreeMap.rotateRight(TreeMap.java:2562)
        at java.base/java.util.TreeMap.fixAfterInsertion(TreeMap.java:2594)
        at java.base/java.util.TreeMap.addEntry(TreeMap.java:770)
        at java.base/java.util.TreeMap.put(TreeMap.java:828)
        at java.base/java.util.TreeMap.put(TreeMap.java:534)
        at SimpleRepro.lambda$main$0(SimpleRepro.java:28)
        at java.base/java.lang.Thread.run(Thread.java:833)
</code></pre></div></div>
<p>but the program would still halt.</p>

<p>Probably only languages that allow you to catch NPEs will encounter this issue.
Other languages will just crash.
After a few runs, I saw 500% cpu utilization.
That’s crazy!
I always thought of race conditions as corrupting the data or deadlocking.
I never though it could cause performance issues.
But it makes sense, you could corrupt the data in a way that creates an infinite loop.</p>

<p>To make extra sure, I created another experiment that uses reflection
against the TreeMap to dump the nodes and their colours.
(In Java, a TreeMap is implemented using a Red-Black tree.)
The cycle in the TreeMap is highlighted in blue.
<img src="/assets/2023-08-20_cpu_util_3200/red_black_tree_cycle.gv.svg" alt="example cycle generated from TreeMap experiment" /></p>

<p>So if you’re searching or putting something not already in the map,
it could get stuck in that infinite loop.</p>

<p>To reproduce the above graph you need to use reflection to access the root, 
and the left and right fields of the <code class="language-plaintext highlighter-rouge">TreeMap.Entry</code>.
You recursively traverse the <code class="language-plaintext highlighter-rouge">TreeMap.Entry</code>s starting from root, keeping
track of the Entries you visited.
If you visit an entry you already visited, you know you’ve hit a loop.
Print all the nodes from visited to show the cycle.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">final</span> <span class="nc">TreeMap</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">treeMap</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Field</span> <span class="n">treeMapRootField</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Field</span> <span class="n">treeMapEntryLeft</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Field</span> <span class="n">treeMapEntryRight</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Field</span> <span class="n">treeMapEntryKey</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Field</span> <span class="n">treeMapEntryColor</span><span class="o">;</span>

<span class="o">...</span>

<span class="kd">public</span> <span class="kt">void</span> <span class="nf">print</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">Exception</span> <span class="o">{</span>
    <span class="n">print</span><span class="o">(</span><span class="n">treeMapRootField</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">treeMap</span><span class="o">),</span> <span class="s">""</span><span class="o">,</span> <span class="k">new</span> <span class="nc">IdentityHashMap</span><span class="o">&lt;&gt;());</span>
<span class="o">}</span>

<span class="kd">private</span> <span class="kt">void</span> <span class="nf">print</span><span class="o">(</span>
    <span class="nc">Object</span> <span class="n">treeMapEntry</span><span class="o">,</span> <span class="nc">String</span> <span class="n">tabs</span><span class="o">,</span> <span class="nc">IdentityHashMap</span><span class="o">&lt;</span><span class="nc">Object</span><span class="o">,</span> <span class="nc">Object</span><span class="o">&gt;</span> <span class="n">visited</span>
<span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span> <span class="o">{</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">treeMapEntry</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">visited</span><span class="o">.</span><span class="na">containsKey</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">))</span> <span class="o">{</span>
        <span class="c1">// in order traversal</span>
        <span class="n">visited</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">,</span> <span class="n">treeMapEntry</span><span class="o">);</span>
        <span class="n">print</span><span class="o">(</span><span class="n">treeMapEntryLeft</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">),</span> <span class="n">tabs</span> <span class="o">+</span> <span class="s">"  "</span><span class="o">,</span> <span class="n">visited</span><span class="o">);</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">tabs</span> <span class="o">+</span> <span class="n">treeMapEntryKey</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">)</span> <span class="o">+</span> <span class="s">":"</span>
            <span class="o">+</span> <span class="o">(</span><span class="n">treeMapEntryColor</span><span class="o">.</span><span class="na">getBoolean</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">)</span> <span class="o">?</span> <span class="s">"BLACK"</span> <span class="o">:</span> <span class="s">"RED"</span><span class="o">));</span>
        <span class="n">print</span><span class="o">(</span><span class="n">treeMapEntryRight</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">),</span> <span class="n">tabs</span> <span class="o">+</span> <span class="s">"  "</span><span class="o">,</span> <span class="n">visited</span><span class="o">);</span>
    <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">treeMapEntry</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">visited</span><span class="o">.</span><span class="na">containsKey</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">))</span> <span class="o">{</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">tabs</span> <span class="o">+</span> <span class="n">treeMapEntryKey</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">)</span>  <span class="o">+</span> <span class="s">":"</span>
            <span class="o">+</span> <span class="o">(</span><span class="n">treeMapEntryColor</span><span class="o">.</span><span class="na">getBoolean</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">)</span> <span class="o">?</span> <span class="s">"BLACK"</span> <span class="o">:</span> <span class="s">"RED"</span><span class="o">)</span>
            <span class="o">+</span> <span class="s">" CYCLE"</span>
        <span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<details>
  <summary>Click to see complete source of TreeMapExplorer that detects and prints the cycle</summary>

  <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">java.lang.reflect.Field</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.Arrays</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.IdentityHashMap</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.TreeMap</span><span class="o">;</span>

<span class="kd">class</span> <span class="nc">TreeMapExplorer</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">TreeMap</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">treeMap</span><span class="o">;</span>
    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Field</span> <span class="n">treeMapRootField</span><span class="o">;</span>
    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Field</span> <span class="n">treeMapEntryLeft</span><span class="o">;</span>
    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Field</span> <span class="n">treeMapEntryRight</span><span class="o">;</span>
    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Field</span> <span class="n">treeMapEntryKey</span><span class="o">;</span>
    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Field</span> <span class="n">treeMapEntryColor</span><span class="o">;</span>

    <span class="kd">static</span> <span class="o">{</span>
        <span class="k">try</span> <span class="o">{</span>
            <span class="n">treeMapRootField</span> <span class="o">=</span> <span class="nc">TreeMap</span><span class="o">.</span><span class="na">class</span><span class="o">.</span><span class="na">getDeclaredField</span><span class="o">(</span><span class="s">"root"</span><span class="o">);</span>
            <span class="n">treeMapRootField</span><span class="o">.</span><span class="na">setAccessible</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>

            <span class="nc">Class</span> <span class="n">treeMapEntryClass</span> <span class="o">=</span> <span class="nc">Arrays</span><span class="o">.</span><span class="na">stream</span><span class="o">(</span><span class="nc">TreeMap</span><span class="o">.</span><span class="na">class</span><span class="o">.</span><span class="na">getDeclaredClasses</span><span class="o">())</span>
                <span class="o">.</span><span class="na">filter</span><span class="o">(</span><span class="n">clazz</span> <span class="o">-&gt;</span> <span class="s">"java.util.TreeMap$Entry"</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">clazz</span><span class="o">.</span><span class="na">getName</span><span class="o">()))</span>
                <span class="o">.</span><span class="na">findAny</span><span class="o">()</span>
                <span class="o">.</span><span class="na">get</span><span class="o">();</span>

            <span class="n">treeMapEntryLeft</span> <span class="o">=</span> <span class="n">treeMapEntryClass</span><span class="o">.</span><span class="na">getDeclaredField</span><span class="o">(</span><span class="s">"left"</span><span class="o">);</span>
            <span class="n">treeMapEntryLeft</span><span class="o">.</span><span class="na">setAccessible</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
            <span class="n">treeMapEntryRight</span> <span class="o">=</span> <span class="n">treeMapEntryClass</span><span class="o">.</span><span class="na">getDeclaredField</span><span class="o">(</span><span class="s">"right"</span><span class="o">);</span>
            <span class="n">treeMapEntryRight</span><span class="o">.</span><span class="na">setAccessible</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
            <span class="n">treeMapEntryKey</span> <span class="o">=</span> <span class="n">treeMapEntryClass</span><span class="o">.</span><span class="na">getDeclaredField</span><span class="o">(</span><span class="s">"key"</span><span class="o">);</span>
            <span class="n">treeMapEntryKey</span><span class="o">.</span><span class="na">setAccessible</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
            <span class="n">treeMapEntryColor</span> <span class="o">=</span> <span class="n">treeMapEntryClass</span><span class="o">.</span><span class="na">getDeclaredField</span><span class="o">(</span><span class="s">"color"</span><span class="o">);</span>
            <span class="n">treeMapEntryColor</span><span class="o">.</span><span class="na">setAccessible</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>

        <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">NoSuchFieldException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
        <span class="o">}</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="nf">TreeMapExplorer</span><span class="o">(</span><span class="nc">TreeMap</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">treeMap</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">treeMap</span> <span class="o">=</span> <span class="n">treeMap</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">print</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">Exception</span> <span class="o">{</span>
        <span class="n">print</span><span class="o">(</span><span class="n">treeMapRootField</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">treeMap</span><span class="o">),</span> <span class="s">""</span><span class="o">,</span> <span class="k">new</span> <span class="nc">IdentityHashMap</span><span class="o">&lt;&gt;());</span>
    <span class="o">}</span>

    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">print</span><span class="o">(</span>
        <span class="nc">Object</span> <span class="n">treeMapEntry</span><span class="o">,</span> <span class="nc">String</span> <span class="n">tabs</span><span class="o">,</span> <span class="nc">IdentityHashMap</span><span class="o">&lt;</span><span class="nc">Object</span><span class="o">,</span> <span class="nc">Object</span><span class="o">&gt;</span> <span class="n">visited</span>
    <span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">treeMapEntry</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">visited</span><span class="o">.</span><span class="na">containsKey</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">))</span> <span class="o">{</span>
            <span class="c1">// in order traversal</span>
            <span class="n">visited</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">,</span> <span class="n">treeMapEntry</span><span class="o">);</span>
            <span class="n">print</span><span class="o">(</span><span class="n">treeMapEntryLeft</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">),</span> <span class="n">tabs</span> <span class="o">+</span> <span class="s">"  "</span><span class="o">,</span> <span class="n">visited</span><span class="o">);</span>
            <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">tabs</span> <span class="o">+</span> <span class="n">treeMapEntryKey</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">)</span> <span class="o">+</span> <span class="s">":"</span>
                <span class="o">+</span> <span class="o">(</span><span class="n">treeMapEntryColor</span><span class="o">.</span><span class="na">getBoolean</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">)</span> <span class="o">?</span> <span class="s">"BLACK"</span> <span class="o">:</span> <span class="s">"RED"</span><span class="o">));</span>
            <span class="n">print</span><span class="o">(</span><span class="n">treeMapEntryRight</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">),</span> <span class="n">tabs</span> <span class="o">+</span> <span class="s">"  "</span><span class="o">,</span> <span class="n">visited</span><span class="o">);</span>
        <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">treeMapEntry</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">visited</span><span class="o">.</span><span class="na">containsKey</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">))</span> <span class="o">{</span>
            <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">tabs</span> <span class="o">+</span> <span class="n">treeMapEntryKey</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">)</span>  <span class="o">+</span> <span class="s">":"</span>
                <span class="o">+</span> <span class="o">(</span><span class="n">treeMapEntryColor</span><span class="o">.</span><span class="na">getBoolean</span><span class="o">(</span><span class="n">treeMapEntry</span><span class="o">)</span> <span class="o">?</span> <span class="s">"BLACK"</span> <span class="o">:</span> <span class="s">"RED"</span><span class="o">)</span>
                <span class="o">+</span> <span class="s">" CYCLE"</span>
            <span class="o">);</span>
        <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div>  </div>
  <p><a href="https://github.com/josephmate/java-by-experiments/blob/main/tree_map_corruption/java/src/main/java/TreeMapExplorer.java">TreeMapExplorer.java available in working project here</a></p>
</details>
<details>
  <summary>Click to see complete source of ExploringTreeMap that drives the experiment</summary>

  <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">java.lang.reflect.Field</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.Arrays</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.TreeMap</span><span class="o">;</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ExploringTreeMap</span> <span class="o">{</span>

    <span class="cm">/**
     * In order to run you need to add these JVM args:
     * &lt;pre&gt;
     * --add-opens java.base/java.util=ALL-UNNAMED
     * &lt;/pre&gt;
     * @param args
     */</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span> <span class="o">{</span>

        <span class="nc">TreeMap</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span> <span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">treeMap</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TreeMap</span><span class="o">&lt;&gt;();</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
            <span class="n">treeMap</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">i</span><span class="o">,</span> <span class="n">i</span><span class="o">);</span>
        <span class="o">}</span>

        <span class="nc">TreeMapExplorer</span> <span class="n">treeMapExplorer</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TreeMapExplorer</span><span class="o">(</span><span class="n">treeMap</span><span class="o">);</span>
        <span class="n">treeMapExplorer</span><span class="o">.</span><span class="na">print</span><span class="o">();</span>
    <span class="o">}</span>


<span class="o">}</span>
</code></pre></div>  </div>
  <p><a href="https://github.com/josephmate/java-by-experiments/blob/main/tree_map_corruption/java/src/main/java/ExploringTreeMap.java">ExploringTreeMap.java available in working project here</a></p>
</details>

<h1 id="related-work">Related Work</h1>

<p>I’m not the first person to write about this issue.
While preparing this article I found:</p>

<ul>
  <li>Ivo Anjo wrote: <a href="https://ivoanjo.me/blog/2018/07/21/writing-to-a-java-treemap-concurrently-can-lead-to-an-infinite-loop-during-reads/">writing to a java treemap concurrently can lead to an infinite loop during reads</a></li>
  <li>Red Hat has a troubleshooting article: <a href="https://access.redhat.com/solutions/58008">High CPU due to multiple Java threads accessing TreeMap simultaneously</a>
    <ul>
      <li>Originally reported as far back as June 20 2011 based on <a href="https://web.archive.org/web/20190715204100/https://access.redhat.com/solutions/58008">web archive</a></li>
    </ul>
  </li>
  <li>There is even a Stack Overflow question about it: <a href="https://stackoverflow.com/questions/56234865/java-process-consumes-more-than-100-cpu">Java Process consumes more than 100% CPU</a></li>
</ul>

<p>However, this article provides a few new perspectives not previously discussed:</p>

<ol>
  <li>Practical code that that reproduces the issue.</li>
  <li>Proposing that only a particular class of languages can encounter this issue
and exploring that hypothesis</li>
  <li>A survey of languages to see if all can reproduce the issue</li>
  <li>A new approach to fixing TreeMap and red black tree to prevent this issue</li>
</ol>

<p>If any of these interest you, please keep reading.</p>

<h1 id="that-code-is-not-realistic">That code is not realistic</h1>

<p>Some might claim that my experimental code is unrealistic.
Who ignores NPEs?
There are two practical ways: uncaught exceptions in executors and services backed by a thread pool.</p>

<h2 id="uncaught-exceptions-in-executor">Uncaught Exceptions in Executor</h2>

<p>We could reproduce this problem in conjunction with another common mistake that suppresses uncaught exceptions.</p>

<p>The below code also reproduces the issue, but with a thread pool.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">final</span> <span class="nc">ExecutorService</span> <span class="n">pool</span> <span class="o">=</span> <span class="nc">Executors</span><span class="o">.</span><span class="na">newFixedThreadPool</span><span class="o">(</span><span class="n">numThreads</span><span class="o">);</span>
<span class="kd">final</span> <span class="nc">TreeMap</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">treeMap</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TreeMap</span><span class="o">&lt;&gt;();</span>

<span class="nc">Random</span> <span class="n">random</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Random</span><span class="o">();</span>
<span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">numThreads</span><span class="o">*</span><span class="n">numUpdatesPerThread</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
    <span class="n">pool</span><span class="o">.</span><span class="na">submit</span><span class="o">(</span> <span class="o">()</span> <span class="o">-&gt;</span> <span class="o">{</span>
        <span class="n">treeMap</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">(</span><span class="mi">10000</span><span class="o">),</span> <span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">(</span><span class="mi">10000</span><span class="o">));</span>
    <span class="o">});</span>
<span class="o">}</span>

<span class="n">pool</span><span class="o">.</span><span class="na">shutdown</span><span class="o">();</span>
<span class="n">pool</span><span class="o">.</span><span class="na">awaitTermination</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="nc">TimeUnit</span><span class="o">.</span><span class="na">DAYS</span><span class="o">);</span>
</code></pre></div></div>
<details>
  <summary>Click here to see complete source of ExecutorUncaughtRepro</summary>

  <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">java.util.Random</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.TreeMap</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.concurrent.ExecutorService</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.concurrent.Executors</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.concurrent.TimeUnit</span><span class="o">;</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ExecutorUncaughtRepro</span> <span class="o">{</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span> <span class="o">{</span>
        <span class="kd">final</span> <span class="kt">int</span> <span class="n">numThreads</span><span class="o">;</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">args</span><span class="o">.</span><span class="na">length</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">numThreads</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">args</span><span class="o">[</span><span class="mi">0</span><span class="o">]);</span>
        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
            <span class="n">numThreads</span> <span class="o">=</span> <span class="mi">5</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="kd">final</span> <span class="kt">int</span> <span class="n">numUpdatesPerThread</span><span class="o">;</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">args</span><span class="o">.</span><span class="na">length</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">numUpdatesPerThread</span> <span class="o">=</span>  <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">args</span><span class="o">[</span><span class="mi">1</span><span class="o">]);</span>
        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
            <span class="n">numUpdatesPerThread</span> <span class="o">=</span> <span class="mi">100000</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="kd">final</span> <span class="nc">ExecutorService</span> <span class="n">pool</span> <span class="o">=</span> <span class="nc">Executors</span><span class="o">.</span><span class="na">newFixedThreadPool</span><span class="o">(</span><span class="n">numThreads</span><span class="o">);</span>
        <span class="kd">final</span> <span class="nc">TreeMap</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">treeMap</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TreeMap</span><span class="o">&lt;&gt;();</span>

        <span class="nc">Random</span> <span class="n">random</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Random</span><span class="o">();</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">numThreads</span><span class="o">*</span><span class="n">numUpdatesPerThread</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
            <span class="n">pool</span><span class="o">.</span><span class="na">submit</span><span class="o">(</span> <span class="o">()</span> <span class="o">-&gt;</span> <span class="o">{</span>
                <span class="n">treeMap</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">(</span><span class="mi">10000</span><span class="o">),</span> <span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">(</span><span class="mi">10000</span><span class="o">));</span>
            <span class="o">});</span>
        <span class="o">}</span>

        <span class="n">pool</span><span class="o">.</span><span class="na">shutdown</span><span class="o">();</span>
        <span class="n">pool</span><span class="o">.</span><span class="na">awaitTermination</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="nc">TimeUnit</span><span class="o">.</span><span class="na">DAYS</span><span class="o">);</span>
    <span class="o">}</span>

<span class="o">}</span>
</code></pre></div>  </div>
  <p><a href="https://github.com/josephmate/java-by-experiments/tree/main/tree_map_corruption/java/src/main/java/ExecutorUncaughtRepro.java">Click here to see ExecutorUncaughtRepro.java in context of working project</a></p>
</details>

<p>When you run it, you’ll see it hang.
Take a thread dump and see the same symptoms:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"pool-1-thread-1" #22 [15356] prio=5 os_prio=0 cpu=17734.38ms elapsed=21.39s tid=0x0000023c45dd3e90 nid=15356 runnable  [0x000000780b4fe000]
   java.lang.Thread.State: RUNNABLE
	at java.util.TreeMap.put(java.base@19.0.1/TreeMap.java:826)
	at java.util.TreeMap.put(java.base@19.0.1/TreeMap.java:534)
	at ExecutorUncaughtRepro.lambda$main$0(ExecutorUncaughtRepro.java:33)
	at ExecutorUncaughtRepro$$Lambda$14/0x00000008010031f0.run(Unknown Source)
	at java.util.concurrent.Executors$RunnableAdapter.call(java.base@19.0.1/Executors.java:577)
	at java.util.concurrent.FutureTask.run(java.base@19.0.1/FutureTask.java:317)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@19.0.1/ThreadPoolExecutor.java:1144)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@19.0.1/ThreadPoolExecutor.java:642)
	at java.lang.Thread.run(java.base@19.0.1/Thread.java:1589)

</code></pre></div></div>
<p>It’s stuck on the TreeMap and really high CPU utilization.</p>

<p>However, when looking at standard out there is nothing!
The thread pool swallowed all the NPEs not giving any indication of problem. 
Unfortunately, this was the case in my situation.</p>

<p>When managing your own thread pools, you need to make sure you:</p>
<ol>
  <li>Register an uncaught exception handler on the thread through a thread factory</li>
  <li>Operate on the futures it return. If you do <code class="language-plaintext highlighter-rouge">future.get()</code> you will get an <code class="language-plaintext highlighter-rouge">ExectionException</code> wrapping the NPE!</li>
</ol>

<h2 id="again-with-grpc">Again with gRPC</h2>

<p>Another way is to have some sort of service back by a thread pool like a gRPC service.
Here I recreate a realistic scenario in gRPC that reproduces the problem.
The service is powered by an unguarded TreeMap.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">addReceipt</span><span class="o">(</span>
    <span class="nc">ReceiptProcessorServiceOuterClass</span><span class="o">.</span><span class="na">AddReceiptRequest</span> <span class="n">req</span><span class="o">,</span>
    <span class="nc">StreamObserver</span><span class="o">&lt;</span><span class="nc">ReceiptProcessorServiceOuterClass</span><span class="o">.</span><span class="na">AddReceiptResponse</span><span class="o">&gt;</span> <span class="n">responseObserver</span>
<span class="o">)</span> <span class="o">{</span>
    <span class="kt">int</span> <span class="n">timestamp</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="na">getTimestamp</span><span class="o">();</span>
    <span class="kt">int</span> <span class="n">totalPrice</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="na">getTotalPrice</span><span class="o">();</span>
    <span class="n">receipts</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">timestamp</span><span class="o">,</span> <span class="n">totalPrice</span><span class="o">);</span>
    <span class="nc">ReceiptProcessorServiceOuterClass</span><span class="o">.</span><span class="na">AddReceiptResponse</span> <span class="n">response</span> <span class="o">=</span> <span class="nc">ReceiptProcessorServiceOuterClass</span><span class="o">.</span><span class="na">AddReceiptResponse</span><span class="o">.</span><span class="na">newBuilder</span><span class="o">().</span><span class="na">build</span><span class="o">();</span>
    <span class="n">responseObserver</span><span class="o">.</span><span class="na">onNext</span><span class="o">(</span><span class="n">response</span><span class="o">);</span>
    <span class="n">responseObserver</span><span class="o">.</span><span class="na">onCompleted</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>
<details>
  <summary>Click to see complete GrpcRepro</summary>

  <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">java.util.ArrayList</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.List</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.Random</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.TreeMap</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.concurrent.TimeUnit</span><span class="o">;</span>

<span class="kn">import</span> <span class="nn">com.google.common.util.concurrent.ListenableFuture</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">io.grpc.ManagedChannel</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">io.grpc.ManagedChannelBuilder</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">io.grpc.Server</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">io.grpc.ServerBuilder</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">io.grpc.stub.StreamObserver</span><span class="o">;</span>

<span class="cm">/**
 * Reproduces the corrupted TreeMap issues through Grpc rather than directly through threads.
 *
 * Demonstrates that the simplified 2 thread reproduce code isn't that unrealistic. Exceptionsm
 * get accidentally swallowed all the time especially if there are RuntimeExceptions like NPEs.
 */</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">GrpcRepro</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span> <span class="o">{</span>
        <span class="kd">final</span> <span class="nc">Server</span> <span class="n">server</span> <span class="o">=</span> <span class="nc">ServerBuilder</span><span class="o">.</span><span class="na">forPort</span><span class="o">(</span><span class="mi">0</span><span class="o">)</span>
            <span class="o">.</span><span class="na">addService</span><span class="o">(</span><span class="k">new</span> <span class="nc">ReceiptProcessorServiceImpl</span><span class="o">())</span>
            <span class="o">.</span><span class="na">build</span><span class="o">()</span>
            <span class="o">.</span><span class="na">start</span><span class="o">();</span>
        <span class="nc">Runtime</span><span class="o">.</span><span class="na">getRuntime</span><span class="o">().</span><span class="na">addShutdownHook</span><span class="o">(</span><span class="k">new</span> <span class="nc">Thread</span><span class="o">(()</span> <span class="o">-&gt;</span> <span class="o">{</span>
            <span class="n">server</span><span class="o">.</span><span class="na">shutdownNow</span><span class="o">();</span>
        <span class="o">}));</span>

        <span class="kd">final</span> <span class="kt">int</span> <span class="n">port</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="na">getPort</span><span class="o">();</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Server started, listening on "</span> <span class="o">+</span> <span class="n">port</span><span class="o">);</span>

        <span class="kd">final</span> <span class="nc">ManagedChannel</span> <span class="n">channel</span> <span class="o">=</span> <span class="nc">ManagedChannelBuilder</span><span class="o">.</span><span class="na">forAddress</span><span class="o">(</span><span class="s">"localhost"</span><span class="o">,</span> <span class="n">port</span><span class="o">)</span>
            <span class="o">.</span><span class="na">usePlaintext</span><span class="o">()</span>
            <span class="o">.</span><span class="na">build</span><span class="o">();</span>
        <span class="kd">final</span> <span class="nc">ReceiptProcessorServiceGrpc</span><span class="o">.</span><span class="na">ReceiptProcessorServiceFutureStub</span> <span class="n">futureStub</span> <span class="o">=</span> <span class="nc">ReceiptProcessorServiceGrpc</span><span class="o">.</span><span class="na">newFutureStub</span><span class="o">(</span><span class="n">channel</span><span class="o">);</span>

        <span class="nc">List</span><span class="o">&lt;</span><span class="nc">ListenableFuture</span><span class="o">&lt;?&gt;&gt;</span> <span class="n">futures</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span>
        <span class="nc">Random</span> <span class="n">random</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Random</span><span class="o">();</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">100_000</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
            <span class="nc">ReceiptProcessorServiceOuterClass</span><span class="o">.</span><span class="na">AddReceiptRequest</span> <span class="n">request</span> <span class="o">=</span> <span class="nc">ReceiptProcessorServiceOuterClass</span><span class="o">.</span><span class="na">AddReceiptRequest</span><span class="o">.</span><span class="na">newBuilder</span><span class="o">()</span>
                <span class="o">.</span><span class="na">setTimestamp</span><span class="o">(</span><span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">(</span><span class="mi">10_000</span><span class="o">))</span>
                <span class="o">.</span><span class="na">setTotalPrice</span><span class="o">(</span><span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">(</span><span class="mi">10_000</span><span class="o">))</span>
                <span class="o">.</span><span class="na">build</span><span class="o">();</span>
            <span class="n">futures</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">futureStub</span><span class="o">.</span><span class="na">addReceipt</span><span class="o">(</span><span class="n">request</span><span class="o">));</span>
        <span class="o">}</span>

        <span class="k">for</span> <span class="o">(</span><span class="nc">ListenableFuture</span><span class="o">&lt;?&gt;</span> <span class="n">future</span> <span class="o">:</span> <span class="n">futures</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">future</span><span class="o">.</span><span class="na">get</span><span class="o">();</span>
        <span class="o">}</span>

        <span class="n">server</span><span class="o">.</span><span class="na">shutdown</span><span class="o">();</span>
        <span class="n">server</span><span class="o">.</span><span class="na">awaitTermination</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="nc">TimeUnit</span><span class="o">.</span><span class="na">DAYS</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="kd">class</span> <span class="nc">ReceiptProcessorServiceImpl</span> <span class="kd">extends</span> <span class="nc">ReceiptProcessorServiceGrpc</span><span class="o">.</span><span class="na">ReceiptProcessorServiceImplBase</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">TreeMap</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span> <span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">receipts</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TreeMap</span><span class="o">&lt;&gt;();</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">addReceipt</span><span class="o">(</span>
        <span class="nc">ReceiptProcessorServiceOuterClass</span><span class="o">.</span><span class="na">AddReceiptRequest</span> <span class="n">req</span><span class="o">,</span>
        <span class="nc">StreamObserver</span><span class="o">&lt;</span><span class="nc">ReceiptProcessorServiceOuterClass</span><span class="o">.</span><span class="na">AddReceiptResponse</span><span class="o">&gt;</span> <span class="n">responseObserver</span>
    <span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">timestamp</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="na">getTimestamp</span><span class="o">();</span>
        <span class="kt">int</span> <span class="n">totalPrice</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="na">getTotalPrice</span><span class="o">();</span>
        <span class="n">receipts</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">timestamp</span><span class="o">,</span> <span class="n">totalPrice</span><span class="o">);</span>
        <span class="nc">ReceiptProcessorServiceOuterClass</span><span class="o">.</span><span class="na">AddReceiptResponse</span> <span class="n">response</span> <span class="o">=</span> <span class="nc">ReceiptProcessorServiceOuterClass</span><span class="o">.</span><span class="na">AddReceiptResponse</span><span class="o">.</span><span class="na">newBuilder</span><span class="o">().</span><span class="na">build</span><span class="o">();</span>
        <span class="n">responseObserver</span><span class="o">.</span><span class="na">onNext</span><span class="o">(</span><span class="n">response</span><span class="o">);</span>
        <span class="n">responseObserver</span><span class="o">.</span><span class="na">onCompleted</span><span class="o">();</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div>  </div>
  <p>Visit <a href="https://github.com/josephmate/java-by-experiments/blob/main/tree_map_corruption/java/src/main/java/GrpcRepro.java">GrpcRepro.java</a> to see source within working project.</p>
</details>
<details>
  <summary>Click to see protobuf</summary>

  <div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">syntax</span> <span class="o">=</span> <span class="s">"proto3"</span><span class="p">;</span>

<span class="kd">message</span> <span class="nc">AddReceiptRequest</span> <span class="p">{</span>
    <span class="kt">int32</span> <span class="na">timestamp</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="kt">int32</span> <span class="na">totalPrice</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">message</span> <span class="nc">AddReceiptResponse</span> <span class="p">{</span>
<span class="p">}</span>

<span class="kd">service</span> <span class="n">ReceiptProcessorService</span> <span class="p">{</span>
    <span class="k">rpc</span> <span class="n">AddReceipt</span><span class="p">(</span><span class="n">AddReceiptRequest</span><span class="p">)</span> <span class="k">returns</span> <span class="p">(</span><span class="n">AddReceiptResponse</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>  </div>
  <p>Visit <a href="https://github.com/josephmate/java-by-experiments/blob/main/tree_map_corruption/java/src/main/protobuf/ReceiptProcessorService.proto">ReceiptProcessorService.proto</a> to see source within working project.</p>
</details>

<p>Dumping the threads gives us:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"grpc-default-executor-23" #54 [8796] daemon prio=5 os_prio=0 cpu=18671.88ms elapsed=175.50s tid=0x00000168b6c707c0 nid=8796 runnable  [0x000000059fbfe000]
   java.lang.Thread.State: RUNNABLE
	at java.util.TreeMap.put(java.base@19.0.1/TreeMap.java:826)
	at java.util.TreeMap.put(java.base@19.0.1/TreeMap.java:534)
	at ReceiptProcessorServiceImpl.addReceipt(GrpcRepro.java:59)
	at ReceiptProcessorServiceGrpc$MethodHandlers.invoke(ReceiptProcessorServiceGrpc.java:185)
	at io.grpc.stub.ServerCalls$UnaryServerCallHandler$UnaryServerCallListener.onHalfClose(ServerCalls.java:182)
	at io.grpc.internal.ServerCallImpl$ServerStreamListenerImpl.halfClosed(ServerCallImpl.java:346)
	at io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$1HalfClosed.runInContext(ServerImpl.java:860)
	at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
	at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@19.0.1/ThreadPoolExecutor.java:1144)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@19.0.1/ThreadPoolExecutor.java:642)
	at java.lang.Thread.run(java.base@19.0.1/Thread.java:1589)
</code></pre></div></div>
<p>showing that TreeMap.put() got stuck on an infinite loop.</p>

<h1 id="how-did-it-happen-rotations">How did it happen? Rotations</h1>

<p>My suspicion is that two threads independently rotate the tree 
in opposite directions, resulting in a cycle.
Or maybe, two overlaping rotations interleave their writes in a way that produces the
cycle.
However, I do not have proof of an interleaving between threads that shows this.</p>

<p>I also suspect that the NPE is necessary.
The problem will not reproduce without hitting an NPE as I saw with my Java experiments.</p>

<h1 id="other-languages">Other languages</h1>

<p>I explore this idea that only languages with NPEs can exhibit this problem by
trying to reproduce this problem in as many languages as I’ve programmed in
before.
If this claim is true, I expect it to only reproduce in
Java, Kotlin, C#, Ruby, Typescript, and Python.
I expect to not be able to reproduce the problem in Go, C++, Rust, and Elixir.</p>

<div style="overflow-x: scroll;">
<table>
  <thead>
    <tr>
      <th>Language</th>
      <th>Affected</th>
      <th>Explanation</th>
      <th>Code</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Java</td>
      <td>yes</td>
      <td>this whole article is based on this</td>
      <td><a href="https://github.com/josephmate/java-by-experiments/tree/main/tree_map_corruption/java/">source</a></td>
    </tr>
    <tr>
      <td>C#</td>
      <td>yes</td>
      <td><a href="https://stackoverflow.com/questions/14909853/is-sorteddictionary-a-red-black-tree">SortedDictionary</a> used red black tree</td>
      <td><a href="https://github.com/josephmate/java-by-experiments/tree/main/tree_map_corruption/csharp/">source</a></td>
    </tr>
    <tr>
      <td>Ruby</td>
      <td>no</td>
      <td>Used red black tree from <a href="http://kanwei.github.io/algorithms/classes/Containers/RubyRBTreeMap.html">kanwei/algorithms</a> but was unable to reproduce the issue. I believe it might not be able to reproduce the problem due to the Global Interpreter Lock (GIL), and how it limits when threads can context switch preventing interleavings of threads that cause an infinite loop.</td>
      <td><a href="https://github.com/josephmate/java-by-experiments/tree/main/tree_map_corruption/ruby/">source</a></td>
    </tr>
    <tr>
      <td>C++</td>
      <td>yes</td>
      <td><a href="https://stackoverflow.com/questions/18414579/what-data-structure-is-inside-stdmap-in-c">used red-black tree</a>. I was expecting it to always segfault first preventing it from hitting the issue.</td>
      <td><a href="https://github.com/josephmate/java-by-experiments/tree/main/tree_map_corruption/cpp/">source</a></td>
    </tr>
    <tr>
      <td>Go</td>
      <td>yes</td>
      <td><a href="https://github.com/emirpasic/gods#redblacktree">has popular datastructures library</a>. Similar to C++, I was expecting it only segfault and not reproduce the infinite loop. I was wrong.</td>
      <td><a href="https://github.com/josephmate/java-by-experiments/tree/main/tree_map_corruption/golang/">source</a></td>
    </tr>
    <tr>
      <td>Rust</td>
      <td>no</td>
      <td>compiler prevented me. I don't know enough about writing unsafe code to reproduce the problem</td>
      <td><a href="https://github.com/josephmate/java-by-experiments/tree/main/tree_map_corruption/rust/">source</a></td>
    </tr>
    <tr>
      <td>Kotlin</td>
      <td>yes</td>
      <td>uses java's TreeMap, same issue expected</td>
      <td></td>
    </tr>
    <tr>
      <td>PHP</td>
      <td>no</td>
      <td>not in standard library and did not find any popular libraries with red black tree</td>
      <td></td>
    </tr>
    <tr>
      <td>JavaScript</td>
      <td>no</td>
      <td><a href="https://stackoverflow.com/questions/40028377/is-it-possible-to-achieve-multithreading-in-nodejs">multithreading model cannot share references</a></td>
      <td></td>
    </tr>
    <tr>
      <td>Typescript</td>
      <td>no</td>
      <td>same argument as JavaScript</td>
      <td></td>
    </tr>
    <tr>
      <td>Python</td>
      <td>no</td>
      <td>no red-black tree in standard library and popular libraries like <a href="https://grantjenks.com/docs/sortedcontainers/implementation.html">Sorted Containers do not use red black tree</a>. despite no red black tree, if I had run the experiment, I would expect to not to be able to reproduce for the same reason as ruby: the GIL.</td>
      <td></td>
    </tr>
    <tr>
      <td>Elixir</td>
      <td>no</td>
      <td>Although there are many third party implementations of the red black trees in Elixir (and Erlang), the programming model makes it impossible: data structures are immutable and interactions between threads are limited to message passing.</td>
      <td></td>
    </tr>
  </tbody>
</table>
</div>

<p>From the table, the most interesting one is C++ because I was not expecting to be able to reproduce the problem due to my hypothesis from the last section.
As a result, I include the details from the experiment here. Similarly, go as unexpected, but trim the article, I left it out. You can see <a href="https://github.com/josephmate/java-by-experiments/tree/main/tree_map_corruption/golang/">Go here</a>.</p>

<p>The code is essentially the same as the Java one, only using C++ standard libraries.
I also added extra printing since I was so shocked that the problem reproduced,
I just wanted to make extra sure.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Equivalent of TreeMap in C++ is std::map</span>
<span class="c1">// Uses same red black tree data structure</span>
<span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">sortedMap</span><span class="p">;</span>

<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">numThreads</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">threads</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">([</span><span class="o">&amp;</span><span class="p">]()</span> <span class="p">{</span>
        <span class="c1">// copy so that we don't use the latest value of i (5)</span>
        <span class="kt">int</span> <span class="n">threadId</span> <span class="o">=</span> <span class="n">threadIdGenerator</span><span class="p">.</span><span class="n">fetch_add</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
        <span class="n">std</span><span class="o">::</span><span class="n">random_device</span> <span class="n">rd</span><span class="p">;</span>
        <span class="n">std</span><span class="o">::</span><span class="n">mt19937</span> <span class="n">gen</span><span class="p">(</span><span class="n">rd</span><span class="p">());</span>
        <span class="n">std</span><span class="o">::</span><span class="n">uniform_int_distribution</span><span class="o">&lt;&gt;</span> <span class="n">dis</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">999</span><span class="p">);</span>
                    
        <span class="kt">int</span> <span class="n">progressThreshold</span> <span class="o">=</span> <span class="n">numUpdates</span> <span class="o">/</span> <span class="n">progressRatio</span><span class="p">;</span>
        <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Thread "</span> <span class="o">&lt;&lt;</span> <span class="n">threadId</span> <span class="o">&lt;&lt;</span> <span class="s">" started."</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">numUpdates</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">try</span> <span class="p">{</span>
                <span class="kt">int</span> <span class="n">key</span> <span class="o">=</span> <span class="n">dis</span><span class="p">(</span><span class="n">gen</span><span class="p">);</span>
                <span class="kt">int</span> <span class="n">value</span> <span class="o">=</span> <span class="n">dis</span><span class="p">(</span><span class="n">gen</span><span class="p">);</span>

                <span class="n">sortedMap</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
            <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">exception</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">"Caught exception on thread "</span> <span class="o">&lt;&lt;</span> <span class="n">threadId</span> <span class="o">&lt;&lt;</span> <span class="s">":"</span> <span class="o">&lt;&lt;</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
            <span class="p">}</span>

            <span class="k">if</span> <span class="p">((</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="n">progressThreshold</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Thread "</span> <span class="o">&lt;&lt;</span> <span class="n">threadId</span> <span class="o">&lt;&lt;</span> <span class="s">": "</span> 
                            <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">100</span> <span class="o">/</span> <span class="n">numUpdates</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">"% complete ("</span> 
                            <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">"/"</span> <span class="o">&lt;&lt;</span> <span class="n">numUpdates</span> <span class="o">&lt;&lt;</span> <span class="s">" updates)</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Thread "</span> <span class="o">&lt;&lt;</span> <span class="n">threadId</span> <span class="o">&lt;&lt;</span> <span class="s">" completed."</span><span class="p">;</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<details>
  <summary>Click here to see complete source code</summary>

  <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;thread&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;map&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;random&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">numThreads</span> <span class="o">=</span> <span class="p">(</span><span class="n">argc</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">)</span> <span class="o">?</span> <span class="n">std</span><span class="o">::</span><span class="n">stoi</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">:</span> <span class="mi">5</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">numUpdates</span> <span class="o">=</span> <span class="p">(</span><span class="n">argc</span> <span class="o">&gt;=</span> <span class="mi">3</span><span class="p">)</span> <span class="o">?</span> <span class="n">std</span><span class="o">::</span><span class="n">stoi</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span> <span class="o">:</span> <span class="mi">100</span><span class="p">;</span>
        <span class="kt">int</span> <span class="n">progressRatio</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>

    <span class="c1">// Equivalent of TreeMap in C++ is std::map</span>
		<span class="c1">// Uses same red black tree data structure</span>
    <span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">sortedMap</span><span class="p">;</span>

    <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="kr">thread</span><span class="o">&gt;</span> <span class="n">threads</span><span class="p">;</span>
    <span class="n">std</span><span class="o">::</span><span class="n">atomic</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">threadIdGenerator</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">numThreads</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">threads</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">([</span><span class="o">&amp;</span><span class="p">]()</span> <span class="p">{</span>
            <span class="c1">// copy so that we don't use the latest value of i (5)</span>
            <span class="kt">int</span> <span class="n">threadId</span> <span class="o">=</span> <span class="n">threadIdGenerator</span><span class="p">.</span><span class="n">fetch_add</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
            <span class="n">std</span><span class="o">::</span><span class="n">random_device</span> <span class="n">rd</span><span class="p">;</span>
            <span class="n">std</span><span class="o">::</span><span class="n">mt19937</span> <span class="n">gen</span><span class="p">(</span><span class="n">rd</span><span class="p">());</span>
            <span class="n">std</span><span class="o">::</span><span class="n">uniform_int_distribution</span><span class="o">&lt;&gt;</span> <span class="n">dis</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">999</span><span class="p">);</span>
                        
            <span class="kt">int</span> <span class="n">progressThreshold</span> <span class="o">=</span> <span class="n">numUpdates</span> <span class="o">/</span> <span class="n">progressRatio</span><span class="p">;</span>
            <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Thread "</span> <span class="o">&lt;&lt;</span> <span class="n">threadId</span> <span class="o">&lt;&lt;</span> <span class="s">" started."</span><span class="p">;</span>
            <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">numUpdates</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">try</span> <span class="p">{</span>
                    <span class="kt">int</span> <span class="n">key</span> <span class="o">=</span> <span class="n">dis</span><span class="p">(</span><span class="n">gen</span><span class="p">);</span>
                    <span class="kt">int</span> <span class="n">value</span> <span class="o">=</span> <span class="n">dis</span><span class="p">(</span><span class="n">gen</span><span class="p">);</span>

                    <span class="n">sortedMap</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
                <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">exception</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">"Caught exception on thread "</span> <span class="o">&lt;&lt;</span> <span class="n">threadId</span> <span class="o">&lt;&lt;</span> <span class="s">":"</span> <span class="o">&lt;&lt;</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
                <span class="p">}</span>

                <span class="k">if</span> <span class="p">((</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="n">progressThreshold</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                        <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Thread "</span> <span class="o">&lt;&lt;</span> <span class="n">threadId</span> <span class="o">&lt;&lt;</span> <span class="s">": "</span> 
                                <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">100</span> <span class="o">/</span> <span class="n">numUpdates</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">"% complete ("</span> 
                                <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">"/"</span> <span class="o">&lt;&lt;</span> <span class="n">numUpdates</span> <span class="o">&lt;&lt;</span> <span class="s">" updates)</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
                <span class="p">}</span>
            <span class="p">}</span>
            <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Thread "</span> <span class="o">&lt;&lt;</span> <span class="n">threadId</span> <span class="o">&lt;&lt;</span> <span class="s">" completed."</span><span class="p">;</span>
        <span class="p">});</span>
    <span class="p">}</span>

    <span class="c1">// Start all threads</span>
    <span class="k">for</span> <span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="kr">thread</span> <span class="o">:</span> <span class="n">threads</span><span class="p">)</span> <span class="p">{</span>
        <span class="kr">thread</span><span class="p">.</span><span class="n">join</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>  </div>
  <p>Visit <a href="https://github.com/josephmate/java-by-experiments/tree/main/tree_map_corruption/cpp/">source</a> to
see code within working project.</p>
</details>

<p>Occasionally, the program segfaults and crashes like before.
This is what I was expecting the worst failure to look like.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./SimpleRepro
zsh: segmentation fault  ./SimpleRepro
</code></pre></div></div>

<p>However, very rarely the output would look like below, indicating the threads got
stuck.
After waiting 10 minutes, the threads never completed.
I did not expect this to happen because I thought it requires a thrown and
swallowed exception. That is not happening here.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./SimpleRepro
Thread 0 started.Thread Thread 0: 10% complete (Thread 10/10012Thread  started.3
started.Thread 4 started.Thread 4: 10% complete (10/100 updates)
 updates)
Thread 0: 20% complete (20/100 updates)
Thread 0: 30% complete (30/100 updates)
Thread 0: 40% complete (40/100 updates)
Thread 1: 10% complete (10/100 updates)
 started.Thread 2: 10% complete (10/100 updates)
Thread 1: 20% complete (20/100 updates)
&lt;nothing output for 5 minutes&gt;
</code></pre></div></div>

<p>From the tool <code class="language-plaintext highlighter-rouge">top</code> we can see that the problem reproduced because of the high cpu
utilization.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>top
PID    COMMAND      %CPU  TIME     ...
59815  SimpleRepro  170.8 08:49.61 ...
</code></pre></div></div>

<p>This shows my claim is false.
I was able to reproduce the problem in Go and C++.
Although they sometimes segfaulted, there were times when they got stuck in the
infinite loop.
In a language like C++, when you reference a null pointer it always segfaults,
so there must be an interleaving of the threads that does not hit a null!
I have no idea why.
I was expecting them to crash given how often I saw NPEs in the Java experiment.</p>

<p>With this knowledge, I went back to my SimpeRepro java experiment and stopped catching the NPE.
After re-running it 12 times, I was still able to reproduce the problem despite not catching the NPE:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"Thread-4" #17 prio=5 os_prio=31 cpu=18597.02ms elapsed=23.79s tid=0x00007f81051ac200 nid=0x6a03 runnable  [0x000070000bcb5000]
   java.lang.Thread.State: RUNNABLE
        at java.util.TreeMap.put(java.base@17.0.3/TreeMap.java:826)
        at java.util.TreeMap.put(java.base@17.0.3/TreeMap.java:534)
        at SimpleRepro.lambda$main$0(SimpleRepro.java:28)
        at SimpleRepro$$Lambda$1/0x0000000800c00a08.run(Unknown Source)
        at java.lang.Thread.run(java.base@17.0.3/Thread.java:833)
</code></pre></div></div>

<p>The other thing that surprised me was languages like Ruby, despite letting you
catch NPEs did not let you reproduce the problem. The Global Interpreter Lock (GIL)
somehow prevented all execution interleavings that would reproduce the problem.</p>

<h1 id="easy-fix-guard-against-concurrent-modification">Easy Fix: Guard against concurrent modification</h1>

<p>The easiest way to fix this was to wrap the TreeMap with <code class="language-plaintext highlighter-rouge">Collections.synchronizedMap</code> or switch to <code class="language-plaintext highlighter-rouge">ConcurrentHashMap</code> and sort on demand.
However, those fixes are boring and did not prevent us from making that mistake and taking down our host.</p>

<h1 id="controversial-fix-track-visited-nodes">Controversial Fix: Track visited nodes</h1>

<p>What if you could safely make the mistake, but not have a cycle?</p>

<p>I modified the red-black tree to record the nodes it has already visited.
The only requires an additional O(lg(n)) memory since it’s limited by the height of the tree.
The height of a red-black tree is guaranteed to be O(lg(n)).
If we encounter a node that we already visited, we throw a <code class="language-plaintext highlighter-rouge">ConcurrentModificationException</code>.
This will not prevent the data corruption,
but will prevent 100% cpu utilization from the infinite loop if someone makes that mistake again in the future.
This would require standard libraries to adopt this technique though which I
don’t think is likely to happen given the extra memory needed.</p>

<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/tree_map_corruption/java/src/main/java/ProtectedTreeMap.java b/tree_map_corruption/java/src/main/java/ProtectedTreeMap.java
index 53c15bb..2713d5a 100644
</span><span class="gd">--- a/tree_map_corruption/java/src/main/java/ProtectedTreeMap.java
</span><span class="gi">+++ b/tree_map_corruption/java/src/main/java/ProtectedTreeMap.java
</span><span class="p">@@ -345,7 +345,9 @@</span> public class ProtectedTreeMap&lt;K,V&gt;
         @SuppressWarnings("unchecked")
             Comparable&lt;? super K&gt; k = (Comparable&lt;? super K&gt;) key;
         Entry&lt;K,V&gt; p = root;
<span class="gi">+        IdentityHashMap&lt;Entry&lt;?,?&gt;, Boolean&gt; visited = new IdentityHashMap&lt;&gt;();
</span>         while (p != null) {
<span class="gi">+            visited.put(p, true);
</span>             int cmp = k.compareTo(p.key);
             if (cmp &lt; 0)
                 p = p.left;
<span class="p">@@ -353,6 +355,10 @@</span> public class ProtectedTreeMap&lt;K,V&gt;
                 p = p.right;
             else
                 return p;
<span class="gi">+
+            if (visited.containsKey(p)) {
+                throw new ConcurrentModificationException("TreeMap corrupted. Loop detected");
+            }
</span>         }
         return null;
     }
<span class="p">@@ -779,6 +785,7 @@</span> public class ProtectedTreeMap&lt;K,V&gt;
     }
 
     private V put(K key, V value, boolean replaceOld) {
<span class="gi">+        IdentityHashMap&lt;Entry&lt;?,?&gt;, Boolean&gt; visited = new IdentityHashMap&lt;&gt;();
</span>         Entry&lt;K,V&gt; t = root;
         if (t == null) {
             addEntryToEmptyMap(key, value);
<span class="p">@@ -790,6 +797,7 @@</span> public class ProtectedTreeMap&lt;K,V&gt;
         Comparator&lt;? super K&gt; cpr = comparator;
         if (cpr != null) {
             do {
<span class="gi">+                visited.put(t, true);
</span>                 parent = t;
                 cmp = cpr.compare(key, t.key);
                 if (cmp &lt; 0)
<span class="p">@@ -803,12 +811,17 @@</span> public class ProtectedTreeMap&lt;K,V&gt;
                     }
                     return oldValue;
                 }
<span class="gi">+
+                if (visited.containsKey(t)) {
+                    throw new ConcurrentModificationException("TreeMap corrupted. Loop detected");
+                }
</span>             } while (t != null);
         } else {
             Objects.requireNonNull(key);
             @SuppressWarnings("unchecked")
             Comparable&lt;? super K&gt; k = (Comparable&lt;? super K&gt;) key;
             do {
<span class="gi">+                                                               visited.put(t, true);
</span>                 parent = t;
                 cmp = k.compareTo(t.key);
                 if (cmp &lt; 0)
<span class="p">@@ -822,6 +835,10 @@</span> public class ProtectedTreeMap&lt;K,V&gt;
                     }
                     return oldValue;
                 }
<span class="gi">+
+                if (visited.containsKey(t)) {
+                    throw new ConcurrentModificationException("TreeMap corrupted. Loop detected");
+                }
</span>             } while (t != null);
         }
         addEntry(key, value, parent, cmp &lt; 0);
</code></pre></div></div>
<details>
  <summary>Click to see complete modified TreeMap.getEntry(Object key)</summary>

  <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * Returns this map's entry for the given key, or {@code null} if the map
 * does not contain an entry for the key.
 *
 * @return this map's entry for the given key, or {@code null} if the map
 *         does not contain an entry for the key
 * @throws ClassCastException if the specified key cannot be compared
 *         with the keys currently in the map
 * @throws NullPointerException if the specified key is null
 *         and this map uses natural ordering, or its comparator
 *         does not permit null keys
 */</span>
<span class="kd">final</span> <span class="nc">Entry</span><span class="o">&lt;</span><span class="no">K</span><span class="o">,</span><span class="no">V</span><span class="o">&gt;</span> <span class="nf">getEntry</span><span class="o">(</span><span class="nc">Object</span> <span class="n">key</span><span class="o">)</span> <span class="o">{</span>
    <span class="c1">// Offload comparator-based version for sake of performance</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">comparator</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span>
        <span class="k">return</span> <span class="nf">getEntryUsingComparator</span><span class="o">(</span><span class="n">key</span><span class="o">);</span>
    <span class="nc">Objects</span><span class="o">.</span><span class="na">requireNonNull</span><span class="o">(</span><span class="n">key</span><span class="o">);</span>
    <span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"unchecked"</span><span class="o">)</span>
        <span class="nc">Comparable</span><span class="o">&lt;?</span> <span class="kd">super</span> <span class="no">K</span><span class="o">&gt;</span> <span class="n">k</span> <span class="o">=</span> <span class="o">(</span><span class="nc">Comparable</span><span class="o">&lt;?</span> <span class="kd">super</span> <span class="no">K</span><span class="o">&gt;)</span> <span class="n">key</span><span class="o">;</span>
    <span class="nc">Entry</span><span class="o">&lt;</span><span class="no">K</span><span class="o">,</span><span class="no">V</span><span class="o">&gt;</span> <span class="n">p</span> <span class="o">=</span> <span class="n">root</span><span class="o">;</span>
    <span class="nc">IdentityHashMap</span><span class="o">&lt;</span><span class="nc">Entry</span><span class="o">&lt;?,?&gt;,</span> <span class="nc">Boolean</span><span class="o">&gt;</span> <span class="n">visited</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">IdentityHashMap</span><span class="o">&lt;&gt;();</span>
    <span class="k">while</span> <span class="o">(</span><span class="n">p</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">visited</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">p</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span>
        <span class="kt">int</span> <span class="n">cmp</span> <span class="o">=</span> <span class="n">k</span><span class="o">.</span><span class="na">compareTo</span><span class="o">(</span><span class="n">p</span><span class="o">.</span><span class="na">key</span><span class="o">);</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">cmp</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="o">)</span>
            <span class="n">p</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="na">left</span><span class="o">;</span>
        <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">cmp</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="o">)</span>
            <span class="n">p</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="na">right</span><span class="o">;</span>
        <span class="k">else</span>
            <span class="k">return</span> <span class="n">p</span><span class="o">;</span>

        <span class="k">if</span> <span class="o">(</span><span class="n">visited</span><span class="o">.</span><span class="na">containsKey</span><span class="o">(</span><span class="n">p</span><span class="o">))</span> <span class="o">{</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">ConcurrentModificationException</span><span class="o">(</span><span class="s">"TreeMap corrupted. Loop detected"</span><span class="o">);</span>
        <span class="o">}</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div>  </div>
  <p>Visit <a href="https://github.com/josephmate/java-by-experiments/blob/main/tree_map_corruption/java/src/main/java/ProtectedTreeMap.java">ProtectedTreeMap.java</a> to see source in context of a working project.</p>
</details>
<details>
  <summary>Click to see complete modified TreeMap.put(K key, V value, boolean replaceOld)</summary>

  <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="no">V</span> <span class="nf">put</span><span class="o">(</span><span class="no">K</span> <span class="n">key</span><span class="o">,</span> <span class="no">V</span> <span class="n">value</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">replaceOld</span><span class="o">)</span> <span class="o">{</span>
    <span class="nc">IdentityHashMap</span><span class="o">&lt;</span><span class="nc">Entry</span><span class="o">&lt;?,?&gt;,</span> <span class="nc">Boolean</span><span class="o">&gt;</span> <span class="n">visited</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">IdentityHashMap</span><span class="o">&lt;&gt;();</span>
    <span class="nc">Entry</span><span class="o">&lt;</span><span class="no">K</span><span class="o">,</span><span class="no">V</span><span class="o">&gt;</span> <span class="n">t</span> <span class="o">=</span> <span class="n">root</span><span class="o">;</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">t</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">addEntryToEmptyMap</span><span class="o">(</span><span class="n">key</span><span class="o">,</span> <span class="n">value</span><span class="o">);</span>
        <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
    <span class="o">}</span>
    <span class="kt">int</span> <span class="n">cmp</span><span class="o">;</span>
    <span class="nc">Entry</span><span class="o">&lt;</span><span class="no">K</span><span class="o">,</span><span class="no">V</span><span class="o">&gt;</span> <span class="n">parent</span><span class="o">;</span>
    <span class="c1">// split comparator and comparable paths</span>
    <span class="nc">Comparator</span><span class="o">&lt;?</span> <span class="kd">super</span> <span class="no">K</span><span class="o">&gt;</span> <span class="n">cpr</span> <span class="o">=</span> <span class="n">comparator</span><span class="o">;</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">cpr</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">do</span> <span class="o">{</span>
            <span class="n">visited</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">t</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span>
            <span class="n">parent</span> <span class="o">=</span> <span class="n">t</span><span class="o">;</span>
            <span class="n">cmp</span> <span class="o">=</span> <span class="n">cpr</span><span class="o">.</span><span class="na">compare</span><span class="o">(</span><span class="n">key</span><span class="o">,</span> <span class="n">t</span><span class="o">.</span><span class="na">key</span><span class="o">);</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">cmp</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="o">)</span>
                <span class="n">t</span> <span class="o">=</span> <span class="n">t</span><span class="o">.</span><span class="na">left</span><span class="o">;</span>
            <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">cmp</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="o">)</span>
                <span class="n">t</span> <span class="o">=</span> <span class="n">t</span><span class="o">.</span><span class="na">right</span><span class="o">;</span>
            <span class="k">else</span> <span class="o">{</span>
                <span class="no">V</span> <span class="n">oldValue</span> <span class="o">=</span> <span class="n">t</span><span class="o">.</span><span class="na">value</span><span class="o">;</span>
                <span class="k">if</span> <span class="o">(</span><span class="n">replaceOld</span> <span class="o">||</span> <span class="n">oldValue</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
                    <span class="n">t</span><span class="o">.</span><span class="na">value</span> <span class="o">=</span> <span class="n">value</span><span class="o">;</span>
                <span class="o">}</span>
                <span class="k">return</span> <span class="n">oldValue</span><span class="o">;</span>
            <span class="o">}</span>

            <span class="k">if</span> <span class="o">(</span><span class="n">visited</span><span class="o">.</span><span class="na">containsKey</span><span class="o">(</span><span class="n">t</span><span class="o">))</span> <span class="o">{</span>
                <span class="k">throw</span> <span class="k">new</span> <span class="nf">ConcurrentModificationException</span><span class="o">(</span><span class="s">"TreeMap corrupted. Loop detected"</span><span class="o">);</span>
            <span class="o">}</span>
        <span class="o">}</span> <span class="k">while</span> <span class="o">(</span><span class="n">t</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">);</span>
    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
        <span class="nc">Objects</span><span class="o">.</span><span class="na">requireNonNull</span><span class="o">(</span><span class="n">key</span><span class="o">);</span>
        <span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"unchecked"</span><span class="o">)</span>
        <span class="nc">Comparable</span><span class="o">&lt;?</span> <span class="kd">super</span> <span class="no">K</span><span class="o">&gt;</span> <span class="n">k</span> <span class="o">=</span> <span class="o">(</span><span class="nc">Comparable</span><span class="o">&lt;?</span> <span class="kd">super</span> <span class="no">K</span><span class="o">&gt;)</span> <span class="n">key</span><span class="o">;</span>
        <span class="k">do</span> <span class="o">{</span>
            <span class="n">visited</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">t</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span>
            <span class="n">parent</span> <span class="o">=</span> <span class="n">t</span><span class="o">;</span>
            <span class="n">cmp</span> <span class="o">=</span> <span class="n">k</span><span class="o">.</span><span class="na">compareTo</span><span class="o">(</span><span class="n">t</span><span class="o">.</span><span class="na">key</span><span class="o">);</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">cmp</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="o">)</span>
                <span class="n">t</span> <span class="o">=</span> <span class="n">t</span><span class="o">.</span><span class="na">left</span><span class="o">;</span>
            <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">cmp</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="o">)</span>
                <span class="n">t</span> <span class="o">=</span> <span class="n">t</span><span class="o">.</span><span class="na">right</span><span class="o">;</span>
            <span class="k">else</span> <span class="o">{</span>
                <span class="no">V</span> <span class="n">oldValue</span> <span class="o">=</span> <span class="n">t</span><span class="o">.</span><span class="na">value</span><span class="o">;</span>
                <span class="k">if</span> <span class="o">(</span><span class="n">replaceOld</span> <span class="o">||</span> <span class="n">oldValue</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
                    <span class="n">t</span><span class="o">.</span><span class="na">value</span> <span class="o">=</span> <span class="n">value</span><span class="o">;</span>
                <span class="o">}</span>
                <span class="k">return</span> <span class="n">oldValue</span><span class="o">;</span>
            <span class="o">}</span>

            <span class="k">if</span> <span class="o">(</span><span class="n">visited</span><span class="o">.</span><span class="na">containsKey</span><span class="o">(</span><span class="n">t</span><span class="o">))</span> <span class="o">{</span>
                <span class="k">throw</span> <span class="k">new</span> <span class="nf">ConcurrentModificationException</span><span class="o">(</span><span class="s">"TreeMap corrupted. Loop detected"</span><span class="o">);</span>
							<span class="o">}</span>
        <span class="o">}</span> <span class="k">while</span> <span class="o">(</span><span class="n">t</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">);</span>
    <span class="o">}</span>
    <span class="n">addEntry</span><span class="o">(</span><span class="n">key</span><span class="o">,</span> <span class="n">value</span><span class="o">,</span> <span class="n">parent</span><span class="o">,</span> <span class="n">cmp</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="o">);</span>
    <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div>  </div>
  <p>Visit <a href="https://github.com/josephmate/java-by-experiments/blob/main/tree_map_corruption/java/src/main/java/ProtectedTreeMap.java">ProtectedTreeMap.java</a> to see source in context of a working project.</p>
</details>

<p>In the above code, you can see that I modified both the get and put methods to
maintain the set of visited nodes and throw a <code class="language-plaintext highlighter-rouge">ConcurrentModificationException</code>
when an already visited node is in the set.</p>

<h1 id="mistakes-happen-make-swiss-cheese">Mistakes Happen: Make Swiss Cheese</h1>

<p>Mistakes happen so it’s important that multiple layers are in place to detect the issue.
Imaging a slice of Swiss cheese, each slice taken from a different block of cheese.
Stacking enough of those slices would result in nothing being able to pass through.</p>

<h2 id="alerts-on-npes">Alerts on NPEs</h2>

<p>We lacked an alarm on any instance of an NPE.
We only had error rate alarms.
This NPE only occurs once per API handler worker thread before which was not enough to trigger our error rate alarms.
On top of that, none of the NPEs were logged because we had an unhandled exception in our Executor.</p>

<h2 id="alerts-on-utilization-anomalies">Alerts on utilization anomalies</h2>

<p>We monitor the cpu utilization and use a naive threshold based approach to alarming.
When the cpu utilization exceeds that threshold, we fire an alarm because it indicates abnormal behaviour.
This is how we discovered the issue.</p>

<h2 id="uncaught-exceptions-on-executors">Uncaught exceptions on Executors</h2>

<p>If you add your work to an executor you must ensure you have an uncaught exception handler.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">AtomicInteger</span> <span class="n">threadNumber</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">AtomicInteger</span><span class="o">(</span><span class="mi">1</span><span class="o">);</span>
<span class="nc">ThreadFactory</span> <span class="n">customThreadFactory</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ThreadFactory</span><span class="o">()</span> <span class="o">{</span>
    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="nc">Thread</span> <span class="nf">newThread</span><span class="o">(</span><span class="nc">Runnable</span> <span class="n">r</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">Thread</span> <span class="n">thread</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Thread</span><span class="o">(</span><span class="n">r</span><span class="o">);</span>
        <span class="n">thread</span><span class="o">.</span><span class="na">setName</span><span class="o">(</span><span class="s">"my-thread-pool-"</span> <span class="o">+</span> <span class="n">threadNumber</span><span class="o">.</span><span class="na">getAndIncrement</span><span class="o">());</span>
        <span class="n">thread</span><span class="o">.</span><span class="na">setUncaughtExceptionHandler</span><span class="o">(</span>
          <span class="o">(</span><span class="n">dyingThread</span><span class="o">,</span> <span class="n">throwable</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="o">{</span>
            <span class="n">logger</span><span class="o">.</span><span class="na">error</span><span class="o">(</span><span class="s">"uncaught exception!"</span><span class="o">,</span> <span class="n">throwable</span><span class="o">);</span>
          <span class="o">}</span>
        <span class="o">);</span>
        <span class="k">return</span> <span class="n">thread</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">};</span>

<span class="nc">ExecutorService</span> <span class="n">executor</span> <span class="o">=</span> <span class="nc">Executors</span><span class="o">.</span><span class="na">newFixedThreadPool</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span> <span class="n">customThreadFactory</span><span class="o">);</span>
</code></pre></div></div>

<p>This code is kind of ugly so you’re better off using</p>

<p><a href="https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/concurrent/BasicThreadFactory.html">Apache Common’s BasicThreadFactory</a>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">new</span> <span class="nc">BasicThreadFactory</span><span class="o">.</span><span class="na">Builder</span><span class="o">()</span>
  <span class="o">.</span><span class="na">namingPattern</span><span class="o">(</span><span class="s">"my-thread-pool-%d"</span><span class="o">)</span>
  <span class="o">.</span><span class="na">uncaughtExceptionHandler</span><span class="o">(</span>
    <span class="o">(</span><span class="n">dyingThread</span><span class="o">,</span> <span class="n">throwable</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="o">{</span>
      <span class="n">logger</span><span class="o">.</span><span class="na">error</span><span class="o">(</span><span class="s">"uncaught exception!"</span><span class="o">,</span> <span class="n">throwable</span><span class="o">);</span>
    <span class="o">}</span>
  <span class="o">)</span>
  <span class="o">.</span><span class="na">build</span><span class="o">();</span>
</code></pre></div></div>
<p>or <a href="https://guava.dev/releases/19.0/api/docs/com/google/common/util/concurrent/ThreadFactoryBuilder.html">guava’s ThreadFactoryBuilder</a>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">new</span> <span class="nc">ThreadFactoryBuilder</span><span class="o">()</span>
  <span class="o">.</span><span class="na">setNameFormat</span><span class="o">(</span><span class="s">"my-thread-pool-%d"</span><span class="o">)</span>
  <span class="o">.</span><span class="na">setUncaughtExceptionHandler</span><span class="o">(</span>
    <span class="o">(</span><span class="n">dyingThread</span><span class="o">,</span> <span class="n">throwable</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="o">{</span>
      <span class="n">logger</span><span class="o">.</span><span class="na">error</span><span class="o">(</span><span class="s">"uncaught exception!"</span><span class="o">,</span> <span class="n">throwable</span><span class="o">);</span>
    <span class="o">}</span>
  <span class="o">)</span>
  <span class="o">.</span><span class="na">build</span><span class="o">()</span>
</code></pre></div></div>

<p>Without a handler, the exception will be swallowed and none of your log monitoring will be able to detect the issue.</p>

<h2 id="code-reviews">Code reviews</h2>

<p>Sometimes, a detail oriented developer will notice the combination of threads
and TreeMap, or even suggest to not use a TreeMap if ordered elements are not
needed. Unfortunately, that didn’t happen in this case.</p>

<h2 id="static-code-analysis">Static code analysis</h2>

<p>Static code analysis tools like SpotBugs (used to be called FindBugs), JLint, and Chord can detect these kinds of issues at build time. See the paper <a href="https://www.sqrlab.ca/papers/SCAM2010.pdf">How Good is Static Analysis at Finding Concurrency Bugs?</a>.
Unfortunately, we didn’t start using them until after the bug.</p>

<h2 id="tests">Tests</h2>

<p>Ensure your tests handle the multithreaded case!
In my case, we did not have multithreaded tests for that part of the code.</p>

<h1 id="conclusion">Conclusion</h1>

<p>Mistakes happen.
Watch out, unprotected concurrent modification data corruption can present itself as infinite loops!
Despite making multiple mistakes, that hid the problem at multiple layers but not all.
As long as you adopt a layered approach, you will be able to respond quickly or
prevent it entirely.</p>]]></content><author><name>Joseph Mate</name></author><category term="Java" /><category term="Race Condition" /><category term="Threads" /><category term="TreeMap" /><category term="Red-Black Tree" /><summary type="html"><![CDATA[A while back my machine was so messed up that I could barely ssh onto it. 3,200% CPU utilization - all 32 cores on the host were fully utilized! Compare that to my last bug where it only used 1 core, 100%]]></summary></entry><entry><title type="html">1,000,000 Concurrent Connections</title><link href="https://josephmate.github.io/2022-04-14-max-connections/" rel="alternate" type="text/html" title="1,000,000 Concurrent Connections" /><published>2022-04-14T09:00:00-04:00</published><updated>2022-04-14T09:00:00-04:00</updated><id>https://josephmate.github.io/max-connections</id><content type="html" xml:base="https://josephmate.github.io/2022-04-14-max-connections/"><![CDATA[<p>I hear the misconception that a server can only accept 65K connections
or a server consumes a port for each accepted connection all the time.
Here is a taste of some of them:</p>

<blockquote>
  <p><a href="https://www.quora.com/Is-it-possible-to-handle-1-billion-connections-simultaneously-in-Java-with-a-single-server">A TCP/IP address only supports 65,000 connections, so you would have to have to assign around 30,000 IP addresses to that server.</a></p>
</blockquote>

<blockquote>
  <p><a href="https://networkengineering.stackexchange.com/questions/48283/is-a-tcp-server-limited-to-65535-clients">There are 65535 TCP port numbers, does that mean only 65535 clients can connect to a TCP server? One might think that this places a hard limit on the number of clients that a single computer/application can maintain.</a></p>
</blockquote>

<blockquote>
  <p><a href="https://serverfault.com/questions/533611/how-do-high-traffic-sites-service-more-than-65535-tcp-connections">If there is a limit on the number of ports one machine can have and a socket can only bind to an unused port number, how do servers experiencing extremely high amounts (more than the max port number) of requests handle this? Is it just done by making the system distributed, i.e., many servers on many machines?</a></p>
</blockquote>

<p>So I put together this article to dispel this myth from three directions:</p>

<ol>
  <li>WhatsApp, a chatting app you have probably used, and Phoenix, a web framework built on top of Elixir, have already demonstrated millions of connections listening to a single port.</li>
  <li>What is theoretically possible based on the TCP/IP protocol</li>
  <li>A simple Java experiment anyone can run on their machine if they are still not convinced.</li>
</ol>

<p>Jump to the summary at the end if you want to skip the details.</p>

<h1 id="experiments">Experiments</h1>

<p>The Phoenix framework which <a href="https://www.phoenixframework.org/blog/the-road-to-2-million-websocket-connections">achieved 2,000,000 concurrent websocket connections</a>.
In the article they demonstrate a chat application where they simulate 2 million users, taking 1 second to broadcast to all users.
They also provide details on the technical challenges they hit with their framework to achieve that benchmark.
Some of the ideas they shared in their article, I used to write this article,
like assigning multiple IPs to overcome the 65k limit on client connections.</p>

<p>WhatsApp also <a href="https://blog.whatsapp.com/1-million-is-so-2011">achieved 2,000,000</a>.
Unfortunately, they are light on the details.
They only reveal the hardware and the OS configuration they used.</p>

<h1 id="theoretical-max">Theoretical Max</h1>

<p>Some think the limit 2<sup>16</sup>=65,536 because that’s all the ports available in the TCP spec.
That limit is true for a single client making outgoing connections to a single IP, port pair.
For instance, my laptop will only be able to make 65,536 connections to
172.217.13.174:443 (google.com:443)
Google would probably block me before I reached 65k connections.
So if you have a use case with intense intertwined communication between two machines using more than 65K concurrent connections,
the client will need to connect from a second IP address,
or the server needs to make a second port available.</p>

<p>For a server listening on a port, each incoming connection <em>DOES NOT</em> consume a port on the server.
The server only consumes the one port that it is listening on.
Secondly connections will be coming from multiple IP addresses.
In the best case the server will be able to listen to all IP addresses, coming from all ports.</p>

<p>Each tcp connection is uniquely defined by:</p>
<ol>
  <li>32 bit source IP (the IP address the connection is coming from)</li>
  <li>16 bit source port (the port on the source IP address the connection is coming from)</li>
  <li>32 bit destination IP (the IP address the connection is going to)</li>
  <li>16 bit destination port (the port on the destination IP address the connection is going to)</li>
</ol>

<p>Then theoretical limit a server can support on a single port is 2<sup>48</sup> which is about 1 quadrillion because:</p>

<ol>
  <li>The server distinguishes the connections from clients’ source IPs and the source ports</li>
  <li>[number of source IP addresses]x[num of source ports]</li>
  <li>32 bits for the address and 16 bits for the port</li>
  <li>Putting that all together: 2<sup>32</sup> x 2<sup>16</sup> =  2<sup>48</sup>.</li>
  <li>Which is about a quadrillion (log(2<sup>48</sup>)/log(10)=14.449)!</li>
</ol>

<h1 id="practical-limit">Practical Limit</h1>
<p>To understand an optimistic practical limit,
I put together some experiments trying to open as many TCP connections 
and have the server send and receive a message on each connection.
The workload is nowhere near as practical as
<a href="https://www.phoenixframework.org/blog/the-road-to-2-million-websocket-connections">Phoenix’s</a>
or
<a href="https://blog.whatsapp.com/1-million-is-so-2011">WhatsApp’s</a>
articles but simpler to run if you wanted to try for yourself.
You will need to overcome three battles to get the experiment to run:
the OS, the JVM, and the TCP/IP protocol.</p>

<h2 id="the-experiment">The experiment</h2>
<p>If you’re interested in the source code, take a look 
<a href="https://github.com/josephmate/java-by-experiments/blob/main/max_connections/src/Main.java">here</a>.</p>

<p>The pseudo code is:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Thread 1:
  open server socket
  for i from 1 to 1 000 000:
    accept incoming connection
  for i from 1 to 1 000 000
    send number i on socket i
  for i from 1 to 1 000 000
    receive number j on socket i
    assert i == j

Thread 2:
  for i from 1 to 1 000 000:
    open client socket to server
  for i from 1 to 1 000 000:
    receive number j on socket i
    assert i == j
  for i from 1 to 1 000 000
    send number i on socket i
</code></pre></div></div>

<h2 id="the-machines">The Machines</h2>
<p>For my machines I tried on my Mac:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2.5 GHz Quad-Core Intel Core i7
16 GB 1600 MHz DDR3
</code></pre></div></div>

<p>and on my Linux desktop:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AMD FX(tm)-6300 Six-Core Processor
8GiB 1600 MHz
</code></pre></div></div>

<h2 id="file-descriptors">File Descriptors</h2>

<p>First battle you’ll encounter is with the operating system.
The defaults severely limit file descriptors.
You’ll see an error like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Exception in thread "main" java.lang.ExceptionInInitializerError
  at java.base/sun.nio.ch.SocketDispatcher.close(SocketDispatcher.java:70)
  at java.base/sun.nio.ch.NioSocketImpl.lambda$closerFor$0(NioSocketImpl.java:1203)
  at java.base/jdk.internal.ref.CleanerImpl$PhantomCleanableRef.performCleanup(CleanerImpl.java:178)
  at java.base/jdk.internal.ref.PhantomCleanable.clean(PhantomCleanable.java:133)
  at java.base/sun.nio.ch.NioSocketImpl.tryClose(NioSocketImpl.java:854)
  at java.base/sun.nio.ch.NioSocketImpl.close(NioSocketImpl.java:906)
  at java.base/java.net.SocksSocketImpl.close(SocksSocketImpl.java:562)
  at java.base/java.net.Socket.close(Socket.java:1585)
  at Main.main(Main.java:123)
Caused by: java.io.IOException: Too many open files
  at java.base/sun.nio.ch.FileDispatcherImpl.init(Native Method)
  at java.base/sun.nio.ch.FileDispatcherImpl.&lt;clinit&gt;(FileDispatcherImpl.java:38)
  ... 9 more
</code></pre></div></div>

<p>Each server socket needs two file descriptors:</p>

<ol>
  <li>A buffer for sending</li>
  <li>A buffer for receiving</li>
</ol>

<p>The same goes for client connections.
As a result, running this experiment on a single machine will require:</p>

<ul>
  <li>1,000,000 connection for the client</li>
  <li>1,000,000 connection for the server</li>
  <li>2 file descriptors per connection</li>
  <li>= 4,000,000 file descriptors</li>
</ul>

<p>For a bigSur 11.4 Mac, you can increase the file descriptor limit with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo sysctl kern.maxfiles=2000000 kern.maxfilesperproc=2000000
kern.maxfiles: 49152 -&gt; 2000000
kern.maxfilesperproc: 24576 -&gt; 2000000
sysctl -a | grep maxfiles
kern.maxfiles: 2000000
kern.maxfilesperproc: 1000000

ulimit -Hn 2000000
ulimit -Sn 2000000
</code></pre></div></div>
<p>as recommended by this <a href="https://superuser.com/a/1644788">stackoverflow answer</a>.</p>

<p>For Ubuntu 20.04, the quickest way is to:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo su
# 2^25 should be more than enough
sysctl -w fs.nr_open=33554432
fs.nr_open = 33554432
ulimit -Hn 33554432
ulimit -Sn 33554432
</code></pre></div></div>

<h2 id="java-file-descriptor-limits">Java File Descriptor Limits</h2>

<p>Now that the operating system is complying,
the JVM doesn’t like what you’re doing with this experiment either.
When you run the experiment you still get the same or similar stack trace.</p>

<p>This <a href="https://superuser.com/a/1398360">stackoverflow answer</a> identifies a JVM flag as the solution:</p>

<blockquote>
  <p><a href="https://docs.oracle.com/en/java/javase/16/docs/specs/man/java.html"><code class="language-plaintext highlighter-rouge">-XX:-MaxFDLimit</code> :     Disables the attempt to set the soft limit for the
number of open file descriptors to the hard limit. By default, this option is
enabled on all platforms, but is ignored on Windows. The only time that you
may need to disable this is on Mac OS, where its use imposes a maximum of
10240, which is lower than the actual system maximum.</a></p>
</blockquote>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>java -XX:-MaxFDLimit Main 6000
</code></pre></div></div>
<p>As the above quote from the javadocs says, this is only required for the Mac.
I was able to get the experiment to run without the flag on Ubuntu.</p>

<h2 id="source-ports">Source Ports</h2>

<p>It still won’t work.
You will encounter a stacktrace like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Exception in thread "main" java.net.BindException: Can't assign requested
address
        at java.base/sun.nio.ch.Net.bind0(Native Method)
        at java.base/sun.nio.ch.Net.bind(Net.java:555)
        at java.base/sun.nio.ch.Net.bind(Net.java:544)
        at java.base/sun.nio.ch.NioSocketImpl.bind(NioSocketImpl.java:643)
        at
java.base/java.net.DelegatingSocketImpl.bind(DelegatingSocketImpl.java:94)
        at java.base/java.net.Socket.bind(Socket.java:682)
        at java.base/java.net.Socket.&lt;init&gt;(Socket.java:506)
        at java.base/java.net.Socket.&lt;init&gt;(Socket.java:403)
        at Main.main(Main.java:137)
</code></pre></div></div>

<p>The final battle is the TCP/IP specification.
Currently we have frozen the server address, server port, and client IP address.
That leaves us with only 16 bits of freedom.
As a result, we can only open 65k connections.</p>

<p>Our experiment goes way beyond that.
We cannot change the server IP nor the server port because that’s the problem
we’re exploring with this experiment.
That leaves us with changing the client IP, giving access to an additional 32 bits of freedom.
As a result, we work around this by conservatively assigning a client IP address for every 5,000 client connections.
This is the same technique they used in 
<a href="https://www.phoenixframework.org/blog/the-road-to-2-million-websocket-connections">Phoenix’s experiment</a>.</p>

<p>On bigSur 11.4 you can add a bunch of fake loopback addresses with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for i in `seq 0 200`; do sudo ifconfig lo0 alias 10.0.0.$i/8 up  ; done 
</code></pre></div></div>

<p>To test to make sure you IP addresses are working you can ping them:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for i in `seq 0 200`; do ping -c 1 10.0.0.$i  ; done 
</code></pre></div></div>

<p>To remove:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for i in `seq 0 200`; do sudo ifconfig lo0 alias 10.0.0.$i  ; done 
</code></pre></div></div>

<p>On Ubuntu 20.04 you need to use the <code class="language-plaintext highlighter-rouge">ip</code> tool instead:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for i in `seq 0 200`; do sudo ip addr add 10.0.0.$i/8 dev lo; done 
</code></pre></div></div>

<p>To remove:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for i in `seq 0 200`; do sudo ip addr del 10.0.0.$i/8 dev lo; done 
</code></pre></div></div>

<h2 id="results">Results</h2>

<p><em>On Mac</em>, I was able to reach 80,000.
However, mysteriously a few minutes after completing the experiment,
my poor Mac crashes everytime without any crash reports in <code class="language-plaintext highlighter-rouge">/Library/Logs/DiagnosticReports</code> so I’m not able to diagnose what happened.</p>

<p>The tcp send and receive buffers on my Mac are 131072 bytes:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysctl net | grep tcp | grep -E '(recv)|(send)'
net.inet.tcp.sendspace: 131072
net.inet.tcp.recvspace: 131072
</code></pre></div></div>

<p>So it might be because I used <code class="language-plaintext highlighter-rouge">80000 connections*131072 bytes per buffer * 2 input and output buffer * 2 client and server connection</code> bytes which is about 39 GB virtual memory.
Or maybe Mac OS didn’t like me using <code class="language-plaintext highlighter-rouge">80,000*2*2=320,000</code> file descriptors.
Unfortunately, I’m not familiar with debugging on Mac without a crash report so if anyone has any resources let me know.</p>

<p><em>On Linux</em>, I was able to reach 840,000!
However, while the experiment ran,
my mouse movements would take a few seconds to register on my screen.
Anything beyond that and my Linux would freeze and become unresponsive.</p>

<p>I used <a href="https://github.com/sysstat/sysstat">sysstat</a> to investigate what resource was in contention.
You can take a look at the graphs sysstat generated <a href="https://raw.githubusercontent.com/josephmate/java-by-experiments/main/max_connections/data/out.840000.svg">here</a>.</p>

<p>I used these commands to get sysstat to record hardware stats on everything and then generate graphs:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sar -o out.840000.sar -A 1 3600 2&gt;&amp;1 &gt; /dev/null  &amp;
sadf -g  out.840000.sar -- -w -r -u -n SOCK -n TCP -B -S -W &gt; out.840000.svg
</code></pre></div></div>

<p>Some interesting facts:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">MBmemfree</code> bottomed out at 96 MB</li>
  <li><code class="language-plaintext highlighter-rouge">MBavail</code> was still 1587MB</li>
  <li><code class="language-plaintext highlighter-rouge">MBmemused</code> was only 1602MB (19.6% of my total 8GB)</li>
  <li><code class="language-plaintext highlighter-rouge">MBswpused</code> peeked at 1086MB (despite memory still available)</li>
  <li>1,680,483 sockets (840k server sockets and 840k client connections plus whatever else was running on my desktop)</li>
  <li>OS decided to start using swap a few seconds into the experiment even though I had more memory</li>
</ul>

<p>On linux <a href="https://stackoverflow.com/questions/7865069/how-to-find-the-socket-buffer-size-of-linux">to find the default size of your send and receive buffers you can use:</a></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># minimum, default and maximum memory size values (in bytes)
cat /proc/sys/net/ipv4/tcp_rmem
4096    131072  6291456
cat /proc/sys/net/ipv4/tcp_wmem
4096    16384   4194304

sysctl net.ipv4.tcp_rmem
net.ipv4.tcp_rmem = 4096        131072  6291456
sysctl net.ipv4.tcp_wmem
net.ipv4.tcp_wmem = 4096        16384   4194304
</code></pre></div></div>

<p>So to support all the connections, I would need 247 GB of virtual memory!</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>131072 bytes for receive 
16384 for write
(131072+16384)*2*840000
=247 GB virtual memory
</code></pre></div></div>

<p>I suspect the buffers were requested, but since only 4 bytes were needed from each, only a fraction of the buffers were used.
Even if I only I load 1 page of memory because I only need to write 4 bytes to write an integer to the buffer:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>getconf PAGESIZE
4096

4096 bytes pagesize
(4096+4096)*2*840000
=13 GB
</code></pre></div></div>
<p>then I use 13GB from touching <code class="language-plaintext highlighter-rouge">2*840000</code> pages of memory.
I have no idea how this didn’t crash!
I’m happy with 840,000 concurrent connections though.</p>

<p>You could improve upon my result if you have more memory,
or further optimize the OS settings like reducing the tcp buffer sizes.
How many can you run? Let me know!</p>

<h1 id="summary">Summary</h1>

<ol>
  <li>Phoenix Framework achieved 2,000,000 connections</li>
  <li>WhatsApp achieved 2,000,000 connections</li>
  <li>Theoretical limit is ~1 quadrillion (1,000,000,000,000,000)</li>
  <li>You will run out of source ports (only 2<sup>16</sup>)</li>
  <li>You can fix this by add loopback client IP addresses</li>
  <li>You will run out of file descriptors</li>
  <li>You can fix this by overriding the file descriptor limits of your OS</li>
  <li>Java will also limit the file descriptors</li>
  <li>You can override this by adding the <code class="language-plaintext highlighter-rouge">-XX:MaxFDLimit</code> JVM argument</li>
  <li>Practical limit on my 16GB Mac is 80,000</li>
  <li>Practical limit on my 8GB Linux is 840,000</li>
</ol>]]></content><author><name>joseph</name></author><category term="Java" /><category term="Server" /><category term="Connections" /><summary type="html"><![CDATA[I hear the misconception that a server can only accept 65K connections or a server consumes a port for each accepted connection all the time. Here is a taste of some of them:]]></summary></entry><entry><title type="html">OdinCodeBrowser: Navigate Code Like in your IDE but on a Static Webpage</title><link href="https://josephmate.github.io/2021-11-28-odin-code-browser/" rel="alternate" type="text/html" title="OdinCodeBrowser: Navigate Code Like in your IDE but on a Static Webpage" /><published>2021-11-28T11:59:00-05:00</published><updated>2021-11-28T11:59:00-05:00</updated><id>https://josephmate.github.io/odin-code-browser</id><content type="html" xml:base="https://josephmate.github.io/2021-11-28-odin-code-browser/"><![CDATA[<p>For the last couple of months I’ve been working on a <a href="https://github.com/josephmate/OdinCodeBrowser/#readme">Java code navigator that fits into your browser</a>.
This won’t replace your IDE.
Code discussions are handled better by github or gitlab.
However, if you want to share links to your code with others that let them navigate all the way down to the JDK, then give this a try.</p>

<p>If you don’t really know what to do with this, then have some fun.
I challenge you to start from <a href="https://josephmate.github.io/OdinCodeBrowser/jdk17/java/util/jar/JarFile.html">JDK’s JarFile</a> and see if you can reach my favourite class: HashMap.</p>

<p>Before I fell in love with Intellij,
I used <a href="https://web.archive.org/web/20150318024036/http://www.grepcode.com/">grepcode</a> to jump into the JDK’s source code to figure out what was going on with my code.
That website died a long time ago.
This is my attempt at a successor.
 You can jump around the repositories by clicking on types, method calls, and variables.
It’s nowhere near Intellij or grepcode yet.
You can look at the massive laundry list in the Future Work section of the readme.
The two things that annoy me the most Odin lacks are chained method calls
(like: thisMethod().someVisibleField.thenAnotherMethod())
and method overloading
(String.valueOf(int) vs String.valueOf(long)).
The coolest things I want to see in the project is linking from Java to native code and generalizing to other languages.</p>

<p>Let me know what you think!</p>]]></content><author><name>joseph.mate</name></author><category term="Java" /><category term="ExecutorService" /><summary type="html"><![CDATA[For the last couple of months I’ve been working on a Java code navigator that fits into your browser. This won’t replace your IDE. Code discussions are handled better by github or gitlab. However, if you want to share links to your code with others that let them navigate all the way down to the JDK, then give this a try.]]></summary></entry><entry><title type="html">100% CPU: My Fault?</title><link href="https://josephmate.github.io/2021-10-03-my-bug-used-up-100cpu-or-did-it/" rel="alternate" type="text/html" title="100% CPU: My Fault?" /><published>2021-10-03T19:22:00-04:00</published><updated>2021-10-03T19:22:00-04:00</updated><id>https://josephmate.github.io/my-bug-used-up-100cpu-or-did-it</id><content type="html" xml:base="https://josephmate.github.io/2021-10-03-my-bug-used-up-100cpu-or-did-it/"><![CDATA[<p>The sirens were place a couple years ago when I received a bug report claiming that I caused 100% CPU util on a VM when it should have been idle.
I was suspicious at first because I try my best to avoid patterns such as <code class="language-plaintext highlighter-rouge">while(true)</code> and <code class="language-plaintext highlighter-rouge">for(;;)</code>.</p>

<p>The support engineer that wrote the initial report included the evidence for the 100% CPU util.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ top
  PID USER      PR  NI    VIRT    RES  %CPU  %MEM     TIME+ S COMMAND
    1 root      20   0 1832.5m  20.6m 100.7   1.0   4:11.04 S java Main
   25 root      20   0    1.6m   1.1m   0.0   0.1   0:00.04 S sh
   38 root      20   0    1.9m   1.2m   0.0   0.1   0:00.00 R  `- top
</code></pre></div></div>
<p>The JVM was indeed using up 100% CPU.
However, how did they track me down?</p>

<h1 id="how-did-they-find-me">How did they find me?</h1>

<p>The bug was triaged by a software developer.
First, he got a list of thread IDs related to the Java process using <code class="language-plaintext highlighter-rouge">top -H -p &lt;pid&gt;</code> with pid from the previous top command:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ top -H -p 1
  PID USER      PR  NI    VIRT    RES  %CPU  %MEM     TIME+ S COMMAND
    1 root      20   0 1832.5m  20.6m   0.0   1.0   0:00.02 S java Main
    7 root      20   0 1832.5m  20.6m   0.0   1.0   0:00.32 S  `- java Main
    8 root      20   0 1832.5m  20.6m   0.0   1.0   0:00.00 S  `- java Main
    9 root      20   0 1832.5m  20.6m   0.0   1.0   0:00.00 S  `- java Main
   10 root      20   0 1832.5m  20.6m   0.0   1.0   0:00.01 S  `- java Main
   11 root      20   0 1832.5m  20.6m   0.0   1.0   0:00.00 S  `- java Main
   12 root      20   0 1832.5m  20.6m   0.0   1.0   0:00.00 S  `- java Main
   13 root      20   0 1832.5m  20.6m   0.0   1.0   0:00.00 S  `- java Main
   14 root      20   0 1832.5m  20.6m   0.0   1.0   0:00.03 S  `- java Main
   15 root      20   0 1832.5m  20.6m   0.0   1.0   0:00.05 S  `- java Main
   16 root      20   0 1832.5m  20.6m   0.0   1.0   0:00.00 S  `- java Main
   17 root      20   0 1832.5m  20.6m   0.7   1.0   0:00.42 S  `- java Main
   18 root      20   0 1832.5m  20.6m  99.9   1.0   3:08.69 R  `- java Main
</code></pre></div></div>
<p>The thread with ID 18 was consuming 100% CPU.</p>

<p>Then he took the thread ID (18) and converted it to hex, resulting in 12.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ printf "%x\n" 18
12
</code></pre></div></div>

<p>Then he grabbed the thread dump using <code class="language-plaintext highlighter-rouge">kill -s QUIT &lt;pid&gt;</code> to get a thread dump sent to standard out.
Then he searched for the string <code class="language-plaintext highlighter-rouge">nid=0x12</code> to find the stack trace of the thread consuming 100% CPU.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ kill -s QUIT 1
...
"joseph-mate-pool-1-thread-1" #8 prio=5 os_prio=0 tid=0x0000558708d94000 nid=0x12 runnable [0x00007f23e77fd000]
   java.lang.Thread.State: RUNNABLE
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:809)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
...
</code></pre></div></div>
<p>Doh! That’s definitely my thread.
I’m glad I provided a thread name factory to my thread pool to make debugging easier for other developers.
It looks like something I put in the <code class="language-plaintext highlighter-rouge">ScheduledThreadPoolExecutor</code> was eating up all the CPU.</p>

<h1 id="was-it-my-bad">Was it my bad?</h1>

<p>My first attempt was to look at what I scheduled to run in the thread pool.
I found the code and, to my surprise, it did not look like it should use very much CPU:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>executorService.scheduleWithFixedDelay(
    () -&gt; doSomethingReallyCheap(),
    0, // Initial delay
    10, // delay
    TimeUnit.MINUTES
);
</code></pre></div></div>
<p>This was something that runs only every 10 minutes and on top of that it was not CPU bound.
There were other similar blocks of code scheduling this kind of work on application startup; again, all of them were IO bound.
On top of that, I intentionally chose <code class="language-plaintext highlighter-rouge">scheduleWithFixedDelay</code> in case it unexpectedly took longer than 10 minutes so that it would not overload the thread pool by adding more work when the previous instance of that task has not completed yet.
At this point I was out of ideas, so I asked a coworker to double check my work.</p>

<p>My co-worker took a look and agreed with me.
It doesn’t look like an issue with <code class="language-plaintext highlighter-rouge">doSomethingReallyCheap()</code>.
However, he took a closer look at the stack trace and noticed it wasn’t stuck in <code class="language-plaintext highlighter-rouge">doSomethingReallyCheap()</code>;
it was actually stuck in <code class="language-plaintext highlighter-rouge">DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:809)</code>!
He suggested I Google a bit and see what comes up.</p>

<h1 id="yes-vindicated">YES! Vindicated!</h1>

<p>Googling for <code class="language-plaintext highlighter-rouge">ScheduledThreadPoolExecutor 100% CPU</code> brings up a StackOverflow post that describes the same symptoms:
<a href="https://stackoverflow.com/questions/53401197/scheduledexecutorservice-consumes-100-cpu-when-corepoolsize-0">ScheduledExecutorService consumes 100% CPU when corePoolSize = 0</a></p>

<p>The author had the exact same line of code as me:</p>
<blockquote>
  <p><code class="language-plaintext highlighter-rouge">ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);</code></p>
</blockquote>

<p>I intentionally used this because I did not want to continuously consume the resources needed for a thread for something that ran once every 10 minutes!
They even warn you not to set it to 0 in the documentation:</p>
<blockquote>
  <p>Additionally, it is almost never a good idea to set corePoolSize to zero or use allowCoreThreadTimeOut because this may leave the pool without threads to handle tasks once they become eligible to run.</p>
</blockquote>

<p>But I was okay with that, because I did not care about waiting for the pool to create a new thread.
The 10 minute delay was not super strict.</p>
<blockquote>
  <p>corePoolSize - the number of threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set
So I was expecting the pool to only keep threads around temporarily.</p>
</blockquote>

<p>At this point, I switched to <code class="language-plaintext highlighter-rouge">corePoolSize=1</code> to work around this unexpected behavior.
I was upset that I had to always consume a thread, but that’s the best I could do with the time available.</p>

<p>However, I was really bothered by that unexpected behavior.
Did I interpret the JavaDocs incorrectly?
Scrolling down, I was very relieved by the top answer.</p>
<blockquote>
  <p>This is a known bug: JDK-8129861 https://bugs.openjdk.java.net/browse/JDK-8129861. It has been fixed in JDK 9.</p>
</blockquote>

<p>YES! Vindicated!</p>

<h1 id="why">WHY!?</h1>

<p>I still wasn’t satisfied.
How could <code class="language-plaintext highlighter-rouge">corePoolSize=0</code> cause JDK to consume 100% CPU?
The details from the JDK bug didn’t give me any hints:</p>

<blockquote>
  <p>Looks like yet another zero-core thread bug, fixed in the Great jsr166 jdk9 integration</p>
</blockquote>

<p>All this tells me is that they planned to make some massive changes to <code class="language-plaintext highlighter-rouge">ScheduledThreadPoolExecutor</code> in JDK9.
It also tells me that they will probably never fix this bug in JDK8.
That’s why if you try this right now in the latest JDK8, you will likely reproduce the problem.
Looks like we’ll need to dive into the source code.
We’ll start our investigation at the top of the stack trace from the thread dump earlier: <code class="language-plaintext highlighter-rouge">ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:809)</code>.
By running a minimal reproducible example in IntelliJ and placing a breakpoint near <code class="language-plaintext highlighter-rouge">DelayedWorkerQueue.poll</code> we can find the infinite loop.
Popping a few stack frames we see <code class="language-plaintext highlighter-rouge">ThreadPoolExecutor.getTask</code> as the infinite loop:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?
    for (;;) {
        ...
        int wc = workerCountOf(c);
        // Are workers subject to culling?
        boolean timed = allowCoreThreadTimeOut || wc &gt; corePoolSize;

        if ((wc &gt; maximumPoolSize || (timed &amp;&amp; timedOut))
            &amp;&amp; (wc &gt; 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        ...
    }
}
</code></pre></div></div>

<ol>
  <li>Note that <code class="language-plaintext highlighter-rouge">keepAliveTime</code> is 0 here.</li>
  <li>Worker count (<code class="language-plaintext highlighter-rouge">wc</code>) is 1 since there is one active thread</li>
  <li><code class="language-plaintext highlighter-rouge">corePoolSize</code> is 0</li>
  <li>This means that <code class="language-plaintext highlighter-rouge">timed = true</code></li>
  <li>Next we check if we can cull a worker</li>
  <li>There are 2 conditions that always prevent us from culling a worker
    <ol>
      <li><code class="language-plaintext highlighter-rouge">wc</code> &gt; 1; but in this case we only have 1 worker</li>
      <li><code class="language-plaintext highlighter-rouge">workQueue.isEmpty()</code> can never be empty since it’s scheduled work. It will always be in the queue.</li>
    </ol>
  </li>
  <li>That means we poll the <code class="language-plaintext highlighter-rouge">workerQueue</code> with <code class="language-plaintext highlighter-rouge">keepAliveTime</code>=<code class="language-plaintext highlighter-rouge">timeout</code>=0!</li>
  <li>This in turn means the poll returns immediately</li>
  <li>Then we’re back to the beginning of the <code class="language-plaintext highlighter-rouge">for(;;)</code> loop and none of the
conditions changed since the last iteration.</li>
</ol>

<p>In contrast, if <code class="language-plaintext highlighter-rouge">corePoolSize</code> is 1, then <code class="language-plaintext highlighter-rouge">time=false</code> and we take from the
<code class="language-plaintext highlighter-rouge">workQueue</code> instead, which blocks.
This explains why setting <code class="language-plaintext highlighter-rouge">corePoolSize=0</code> is a workaround.</p>

<p>This might be fixable if we change the <code class="language-plaintext highlighter-rouge">wc &gt; 1</code> condition to <code class="language-plaintext highlighter-rouge">wc &gt; 0</code> and change
the <code class="language-plaintext highlighter-rouge">isEmpty()</code> condition to check if something needs to execute soon. However,
this creates a massive design issue. We are using the current worker thread to 
poll for tasks.
We can’t just change the cull worker condition to <code class="language-plaintext highlighter-rouge">wc &gt; 0</code>. 
We should have heeded the JavaDoc’s warning and not used <code class="language-plaintext highlighter-rouge">corePoolSize=0</code>.</p>

<p>To fix the JDK limitation, maybe we can schedule a new thread to be created when the scheduled task’s deadline approaches and exit the current thread!
However, there’s a lot of stuff left to figure out.
For example, what thread is going to do the work of creating the thread when the scheduled task needs to run?</p>

<h1 id="what-could-i-have-done-better">What could I have done better?</h1>

<p><strong>RTFM:</strong> It’s impossible for me to have known that <code class="language-plaintext highlighter-rouge">corePoolSize=0</code> would not work.
I could have read the JavaDocs more closely and heeded their warning of avoiding <code class="language-plaintext highlighter-rouge">corePoolSize=0</code>.
However, even if I had read that line, I don’t think it would have stopped me because in my mind the use case made sense.</p>

<p><strong>Testing:</strong> What’s embarrassing is that the problem is reproducible every time and 100% CPU should be pretty easy to spot.
I should have monitored the CPU while testing it.
But I only look at the CPU when testing my code for a performance change.
I did not anticipate this change to have a performance impact.
Should I check the CPU for all of my changes?
Or should there be an automated test that detects significant differences in CPU utilization between code changes?</p>

<p><strong>Upgrade:</strong> If I kept the JDK updated, I would have never encountered this problem.
The problem occurred back in 2018 or 2019, which was around the time JDK 11 was released which would have included the fix.</p>

<p><strong>Unoptimized:</strong> I never should have tried to optimize the thread pool!
Two commenters summed it up nicely, calling me out on my sin.</p>

<blockquote>
  <p>You’re guilty of one of the biggest crimes that you can commit in all of Computer Science - preemptive optimization. Consuming a single thread in perpetuity uses almost no meaningful resources. Any attempt to optimize this was pointless at best, and dangerous at worst - as you found out. -<a href="https://www.reddit.com/r/programming/comments/q1w4od/comment/hfi5vx3/">/u/SirSagramore/</a></p>
</blockquote>

<blockquote>
  <p>I’ve found that it’s rarely a good idea to optimise prematurely without facts/numbers to back it up. It’s just one OS thread and the OS is probably smarter than the developer when it comes to managing resources in the long run. -<a href="https://www.reddit.com/r/programming/comments/q1w4od/comment/hfi9478/">/u/wot-teh-phuck</a></p>
</blockquote>

<h1 id="try-it-yourself">Try it yourself</h1>

<p>If you want to try this yourself, compile and run the below code using JDK8.
It reproduced at the time I wrote this article because OpenJDK only fixed the issue in JDK9.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public final class Main {

  public static void main(String [] args) throws Exception {
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);
    executorService.scheduleWithFixedDelay(
        () -&gt; System.out.println("Hello World!"),
        0, // Initial delay
        10, // delay
        TimeUnit.MINUTES
    );
    while (true) {
      Thread.sleep(10000);
    }
  }

}
</code></pre></div></div>

<p>Just to double check, I tried out the above code with JDK9 and CPU util was low.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ top
  PID USER      PR  NI    VIRT    RES  %CPU  %MEM     TIME+ S COMMAND
    1 root      20   0 3008.5m  29.1m   0.0   1.5   0:00.76 S java Main
   27 root      20   0    1.6m   0.0m   0.0   0.0   0:00.02 S sh
   34 root      20   0    7.9m   1.3m   0.0   0.1   0:00.01 R  `- top
</code></pre></div></div>

<h1 id="final-thoughts">Final Thoughts</h1>

<p>I was relieved that I was not the culprit.
However, I still share some of blame because I could have caught this issue earlier by monitoring the CPU while testing.
Fortunately, I’m grateful we had strong test engineers that caught it before it was released.
What do you think?
Was this my fault?</p>

<p>Update: Yes it was my fault. Premature optimization is the root of all evil.</p>

<h1 id="thanks-to">Thanks to:</h1>

<ul>
  <li><a href="https://github.com/Omar-Elrefaei">Omar Elrefaei</a> for the <a href="https://github.com/josephmate/josephmate.github.io/pull/42">PR</a> that fixed the
formatting of this document.</li>
  <li><a href="https://www.reddit.com/r/programming/comments/q1w4od/comment/hfhw9a5/?utm_source=share&amp;utm_medium=web2x&amp;context=3">/u/thorn-harvestar/</a>, <a href="https://www.reddit.com/r/programming/comments/q1w4od/comment/hfhabww/">/u/philipTheDev/</a>, and <a href="https://www.reddit.com/r/java/comments/q1wlyw/comment/hfhq8pg/">/u/vips7L/</a>: for identifying another root cause. I shouldn’t be using JDK8 anymore!</li>
  <li><a href="https://www.reddit.com/r/programming/comments/q1w4od/comment/hfi5vx3/">/u/SirSagramore/</a> and <a href="https://www.reddit.com/r/programming/comments/q1w4od/comment/hfi9478/">/u/wot-teh-phuck</a>: for proving that it really was my fault :(. Premature optimization is the root of all evil.</li>
</ul>]]></content><author><name>joseph.mate</name></author><category term="Java" /><category term="ExecutorService" /><summary type="html"><![CDATA[The sirens were place a couple years ago when I received a bug report claiming that I caused 100% CPU util on a VM when it should have been idle. I was suspicious at first because I try my best to avoid patterns such as while(true) and for(;;).]]></summary></entry><entry><title type="html">Javascript Does Not Need a StringBuilder</title><link href="https://josephmate.github.io/2020-07-27-javascript-does-not-need-stringbuilder/" rel="alternate" type="text/html" title="Javascript Does Not Need a StringBuilder" /><published>2020-07-27T20:14:00-04:00</published><updated>2020-07-27T20:14:00-04:00</updated><id>https://josephmate.github.io/javascript-does-not-need-stringbuilder</id><content type="html" xml:base="https://josephmate.github.io/2020-07-27-javascript-does-not-need-stringbuilder/"><![CDATA[<p>Today I learned that Javascript does not need a StringBuilder for accumulating a large number of concatinations.
As a Java programmer, that came as a shock to me.
This article summarizes my exploration of this fact.</p>

<h1 id="effective-java">Effective Java</h1>
<p>A StringBuilder is grilled into Java programmers. Effective Java
<a href="https://www.amazon.ca/Effective-Java-3rd-Joshua-Bloch/dp/0134685997">[1]</a>
says, “Item 51: Beware the performance of string concatenation.”
Many books, articles, blog posts and stack overflow questions have extensively covered this in detail 
<a href="http://www.thefinestartist.com/effective-java/51">[2]</a>
<a href="http://jtechies.blogspot.com/2012/07/item-51-beware-performance-of-string.html">[3]</a>
<a href="https://www.corejavaguru.com/effective-java/items/51">[4]</a>
<a href="https://dzone.com/articles/string-concatenation-performacne-improvement-in-ja">[5]</a>
<a href="https://stackoverflow.com/questions/4645020/when-to-use-stringbuilder-in-java">[6]</a>
<a href="https://stackoverflow.com/questions/10078912/best-practices-performance-mixing-stringbuilder-append-with-string-concat">[7]</a>
<a href="https://stackoverflow.com/questions/1532461/stringbuilder-vs-string-concatenation-in-tostring-in-java">[8]</a>.</p>

<p>Now you can see why it came as such a shock to me.
I assumed Javascript would do the same thing as Java to maintain the immutability of strings.
Java allocates a new array containing the result of each successive concatenation resulting in the O(N^2) runtime complexity.</p>

<h1 id="experiments">Experiments</h1>
<p>When I first learned this from a co-worker, I couldn’t believe it!
I put together some experiments to confirm.
I measured how long it would take to do different powers of 2 of concatenations in Java and Javascript.
I am not interested in a comparison between the languages.
I am curious about how runtime grows as the number of concatenations grows.</p>

<p>If you would like to checkout a copy of the source code take a look at the last two sections (Java source and Javascript source) of this page or check <a href="https://github.com/josephmate/JavaVsJavascriptStringBuilder">my repo</a>.</p>

<p>You can try out the Javascript experiment in your browser at my <a href="https://josephmate.github.io/JavaVsJavascriptStringBuilder/">git hub page</a>.</p>

<p>I’ve summarized how long each number of concats took in the table below.
I looked at using naive += String concatenation, Java’s StringBuilder, and Javascript’s Array.join.</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th style="text-align: right"># Concats</th>
      <th style="text-align: right"> </th>
      <th style="text-align: right"> </th>
      <th style="text-align: right"> </th>
      <th style="text-align: right"> </th>
      <th style="text-align: right"> </th>
      <th style="text-align: right"> </th>
      <th style="text-align: right"> </th>
      <th style="text-align: right"> </th>
      <th style="text-align: right"> </th>
    </tr>
    <tr>
      <th>Algorithm</th>
      <th style="text-align: right">2^18</th>
      <th style="text-align: right">2^19</th>
      <th style="text-align: right">2^20</th>
      <th style="text-align: right">2^21</th>
      <th style="text-align: right">2^22</th>
      <th style="text-align: right">2^23</th>
      <th style="text-align: right">2^24</th>
      <th style="text-align: right">2^25</th>
      <th style="text-align: right">2^26</th>
      <th style="text-align: right">2^27</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Java8 naive += (ms)</td>
      <td style="text-align: right">21945</td>
      <td style="text-align: right">94077</td>
      <td style="text-align: right">412675</td>
      <td style="text-align: right">1886317</td>
      <td style="text-align: right">8529431</td>
      <td style="text-align: right">TOO LONG</td>
      <td style="text-align: right">TOO LONG</td>
      <td style="text-align: right">TOO LONG</td>
      <td style="text-align: right">TOO LONG</td>
      <td style="text-align: right">TOO LONG</td>
    </tr>
    <tr>
      <td>Java8 StringBuilder (ms)</td>
      <td style="text-align: right">5</td>
      <td style="text-align: right">6</td>
      <td style="text-align: right">11</td>
      <td style="text-align: right">39</td>
      <td style="text-align: right">70</td>
      <td style="text-align: right">119</td>
      <td style="text-align: right">209</td>
      <td style="text-align: right">492</td>
      <td style="text-align: right">898</td>
      <td style="text-align: right">1738</td>
    </tr>
    <tr>
      <td>Java14 naive += (ms)</td>
      <td style="text-align: right">9726</td>
      <td style="text-align: right">38619</td>
      <td style="text-align: right">173218</td>
      <td style="text-align: right">860218</td>
      <td style="text-align: right">4435485</td>
      <td style="text-align: right">TOO LONG</td>
      <td style="text-align: right">TOO LONG</td>
      <td style="text-align: right">TOO LONG</td>
      <td style="text-align: right">TOO LONG</td>
      <td style="text-align: right">TOO LONG</td>
    </tr>
    <tr>
      <td>Java14 StringBuilder (ms)</td>
      <td style="text-align: right">2</td>
      <td style="text-align: right">5</td>
      <td style="text-align: right">12</td>
      <td style="text-align: right">20</td>
      <td style="text-align: right">41</td>
      <td style="text-align: right">115</td>
      <td style="text-align: right">185</td>
      <td style="text-align: right">379</td>
      <td style="text-align: right">943</td>
      <td style="text-align: right">1754</td>
    </tr>
    <tr>
      <td>Chrome Javascript naive += (ms)</td>
      <td style="text-align: right">30</td>
      <td style="text-align: right">79</td>
      <td style="text-align: right">144</td>
      <td style="text-align: right">408</td>
      <td style="text-align: right">906</td>
      <td style="text-align: right">1650</td>
      <td style="text-align: right">3418</td>
      <td style="text-align: right">7411</td>
      <td style="text-align: right">14548</td>
      <td style="text-align: right">OOM</td>
    </tr>
    <tr>
      <td>Chrome Javascript Array.join (ms)</td>
      <td style="text-align: right">18</td>
      <td style="text-align: right">37</td>
      <td style="text-align: right">71</td>
      <td style="text-align: right">156</td>
      <td style="text-align: right">318</td>
      <td style="text-align: right">621</td>
      <td style="text-align: right">1416</td>
      <td style="text-align: right">3275</td>
      <td style="text-align: right">5385</td>
      <td style="text-align: right">OOM</td>
    </tr>
    <tr>
      <td>Firefox Javascript naive += (ms)</td>
      <td style="text-align: right">14</td>
      <td style="text-align: right">12</td>
      <td style="text-align: right">42</td>
      <td style="text-align: right">68</td>
      <td style="text-align: right">172</td>
      <td style="text-align: right">272</td>
      <td style="text-align: right">518</td>
      <td style="text-align: right">1836</td>
      <td style="text-align: right">5075</td>
      <td style="text-align: right">9850</td>
    </tr>
    <tr>
      <td>Firefox Javascript Array.join (ms)</td>
      <td style="text-align: right">11</td>
      <td style="text-align: right">18</td>
      <td style="text-align: right">44</td>
      <td style="text-align: right">70</td>
      <td style="text-align: right">149</td>
      <td style="text-align: right">384</td>
      <td style="text-align: right">766</td>
      <td style="text-align: right">1846</td>
      <td style="text-align: right">3655</td>
      <td style="text-align: right">10912</td>
    </tr>
    <tr>
      <td>NodeJS Javascript naive += (ms)</td>
      <td style="text-align: right">29</td>
      <td style="text-align: right">112</td>
      <td style="text-align: right">206</td>
      <td style="text-align: right">460</td>
      <td style="text-align: right">813</td>
      <td style="text-align: right">2233</td>
      <td style="text-align: right">3599</td>
      <td style="text-align: right">6384</td>
      <td style="text-align: right">13266</td>
      <td style="text-align: right">33434</td>
    </tr>
    <tr>
      <td>NodeJS Javascript Array.join (ms)</td>
      <td style="text-align: right">22</td>
      <td style="text-align: right">54</td>
      <td style="text-align: right">93</td>
      <td style="text-align: right">245</td>
      <td style="text-align: right">425</td>
      <td style="text-align: right">753</td>
      <td style="text-align: right">1920</td>
      <td style="text-align: right">4048</td>
      <td style="text-align: right">20333</td>
      <td style="text-align: right">OOM</td>
    </tr>
  </tbody>
</table>

<p>At 2^23, the naive Java String concatenation took too long to run.
I gave up at 2^22 when it took over 2 hours!
Each doubling of the input size results in more than double the runtime, as we expected because of the O(N^2) complexity.
I tested both Java8 and and Java14, expecting it to be optimized.
Even though these stack overflow articles
<a href="https://stackoverflow.com/questions/1532461/stringbuilder-vs-string-concatenation-in-tostring-in-java/1532499#1532499">[9]</a> and
<a href="https://stackoverflow.com/questions/14927630/java-string-concat-vs-stringbuilder-optimised-so-what-should-i-do">[10]</a>
say its been optimized, the optimization does not fix the concatenation in the loop.
I believe the optimization cannot apply over multiple statements, only with in a single statement.
However <a href="http://openjdk.java.net/jeps/280">JEP 280: Indify String Concatenation</a> has laid the groundwork to more easily optimize String concatenation in the future without having to tweak the the bytecode on the compiler.</p>

<p>With Javascript the growth looks kind of linear.
Lets investigate with a plot.
We won’t plot the naive Java concatenation since it grows too quickly and the scale would make it difficult to analyze the growth of the remaining methods.
I also left out Java 14 StringBuilder since it performed almost the same as Java 8.</p>

<script src="https://d3js.org/d3.v4.js"></script>

<!-- Color Scale -->
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>

<div id="chart"></div>

<script>

// https://stackoverflow.com/questions/448981/which-characters-are-valid-in-css-class-names-selectors
// begin with underscore (_), a hyphen (-), or a letter(a–z),
// followed by any number of hyphens, underscores, letters, or numbers
// if the first character is a hyphen, the second character must2 be a letter or underscore
// name must be at least 2 characters long
function toClassName(humanReadableString) {
  return humanReadableString
    .replace("#", "")
    .replace(" ", "")
    .replace("+", "")
    .replace("=", "")
    .replace("(", "")
    .replace(")", "")
    .replace(".", "")
     ;
}

function isNumber(value) {
  return Number.isFinite(value);
}

function lastNumberPoint(dataPoints) {
  for (var i = dataPoints.length - 1; i >= 0; i--) {
    if (isNumber(dataPoints[i].value)) {
      return dataPoints[i];
    }
  }
  return dataPoints[dataPoints.length - 1];
}

// based on
// https://www.d3-graph-gallery.com/graph/connectedscatter_legend.html
// 1. modified the legend to display vertically since there's more lines
// and more text
// 2. sanitize column names for use in CSS class selectors
// 3. last value is missing, so use a loop to find the last value instead
var margin = {top: 10, right: 100, bottom: 30, left: 100},
    width = 700 - margin.left - margin.right,
    height = 700 - margin.top - margin.bottom;

var svg = d3.select("#chart")
  .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");


//Read the data
d3.csv("/data/2020-07-28_experiment_data.csv", function(data) {

    // List of groups (here I have one group per column)
    var allGroup = [
      "Java8 StringBuilder (ms)",
      "Chrome Javascript naive += (ms)",
      "Chrome Javascript Array.join (ms)",
      "Firefox Javascript naive += (ms)",
      "Firefox Javascript Array.join (ms)",
      "NodeJS Javascript naive += (ms)",
      "NodeJS Javascript Array.join (ms)"
]

    // Reformat the data: we need an array of arrays of {x, y} tuples
    var dataReady = allGroup.map( function(grpName) { // .map allows to do something for each element of the list
      return {
        name: grpName,
        values: data.map(function(d) {
          return {time: d["# concats"], value: +d[grpName]};
        })
      };
    });
    // I strongly advise to have a look to dataReady with
    console.log(dataReady)

    // A color scale: one color for each group
    var myColor = d3.scaleOrdinal()
      .domain(allGroup)
      .range(d3.schemeSet2);

    // Add X axis --> it is a date format
    var x = d3.scaleLinear()
      .domain([0,134217728])
      .range([ 0, width ]);
    svg.append("g")
      .attr("transform", "translate(0," + height + ")")
      // https://observablehq.com/@d3/axis-ticks
      .call(d3.axisBottom(x).ticks(10, "s"));

    // Add Y axis
    var y = d3.scaleLinear()
      .domain( [0,33434])
      .range([ height, 0 ]);
    svg.append("g")
      .call(d3.axisLeft(y));

    // Add the lines
    var line = d3.line()
      .x(function(d) { return x(+d.time) })
      .y(function(d) { return y(+d.value) })
    svg.selectAll("myLines")
      .data(dataReady)
      .enter()
      .append("path")
        .attr("class", function(d){ return toClassName(d.name) })
        .attr("d", function(d){ return line(d.values) } )
        .attr("stroke", function(d){ return myColor(d.name) })
        .style("stroke-width", 4)
        .style("fill", "none")

    // Add the points
    svg
      // First we need to enter in a group
      .selectAll("myDots")
      .data(dataReady)
      .enter()
        .append('g')
        .style("fill", function(d){ return myColor(d.name) })
        .attr("class", function(d){ return toClassName(d.name) })
      // Second we need to enter in the 'values' part of this group
      .selectAll("myPoints")
      .data(function(d){ return d.values })
      .enter()
      .append("circle")
        .attr("cx", function(d) { return x(d.time) } )
        .attr("cy", function(d) { return y(d.value) } )
        .attr("r", 5)
        .attr("stroke", "white")

    // Add a label at the end of each line
    svg
      .selectAll("myLabels")
      .data(dataReady)
      .enter()
        .append('g')
        .append("text")
          .attr("class", function(d){ return toClassName(d.name) })
          .datum(function(d) { return {name: d.name, value: lastNumberPoint(d.values)}; }) // keep only the last value of each time series
          .attr("transform", function(d) { 
            if ( d.value.value > 30000) {
            return "translate(" + x(d.value.time-30000000) + "," + y(d.value.value-1000) + ")"; 
            }
            return "translate(" + x(d.value.time-30000000) + "," + y(d.value.value+1000) + ")"; 
            }) // Put the text at the position of the last point
          .attr("x", 12) // shift the text a bit more right
          .text(function(d) { return d.name.replace(" (ms)", ""); })
          .style("fill", function(d){ return myColor(d.name) })
          .style("font-size", 15)

    // Add a legend (interactive)
    svg
      .selectAll("myLegend")
      .data(dataReady)
      .enter()
        .append('g')
        .append("text")
          .attr('x', function(d,i){ return 30 })
          .attr('y', function(d,i){ return 30 + i*20})
          .text(function(d) { return d.name; })
          .style("fill", function(d){ return myColor(d.name) })
          .style("font-size", 15)
        .on("click", function(d){
          // is the element currently visible ?
          currentOpacity = d3.selectAll("." + toClassName(d.name)).style("opacity")
          // Change the opacity: from 0 to 1 or from 1 to 0
          d3.selectAll("." + toClassName(d.name)).transition().style("opacity", currentOpacity == 1 ? 0:1)

        })
});
</script>

<p>After plotting, the growth looks linear for all of these variations.
However, it’s best to keep reading for a bit of complexity analysis.</p>

<h1 id="why-javascript-does-not-need-a-stringbuilder">Why Javascript Does not Need a StringBuilder</h1>

<p>Following the experiments, I wanted to know why.
My research led me to <a href="https://www.mail-archive.com/es-discuss@mozilla.org/msg10071.html">this email chain</a> where Dr. Axel Rauschmayer
proposes adding StringBuilder to the next version of ECMAScript:</p>
<blockquote>
  <p>Is this worthy of ES.next support? Or does it belong into a library?</p>

  <p>The two concatenation approaches I know of are:</p>
  <ol>
    <li>via +=</li>
    <li>push() into an array, join() it after the last push()</li>
  </ol>

  <p>(1) can’t possibly be efficient, but if (2) is OK on all(!) platforms, then a 
library would be OK. However, given how frequently this is used, I would like 
this to become part of the standard library.</p>
</blockquote>

<p><a href="https://www.mail-archive.com/es-discuss@mozilla.org/msg10129.html">Tom Schuster responds</a> that it’s not necessary.</p>
<blockquote>
  <p>(1) is in  fact really good optimized in modern engines.  (In case you
are interested search for “Ropes: an alternative to strings”)</p>

  <p>I think today it’s not a very good idea to propose methods on probably
existing performance problems.</p>
</blockquote>

<p>I did more digging and learned that ropes are a datastructure the allow immutable String concatenations in O(lgN) time.</p>

<p><a href="https://hg.mozilla.org/mozilla-central/file/tip/js/src/vm/StringType.h#l73">Firefox’s Javascript VM’s sourcecode</a> comments on what Tom Schuster was saying the email chain.</p>

<blockquote>
  <p>To avoid O(n^2) char buffer copying, a “rope” node (JSRope) can be created
   to represent a delayed string concatenation. Concatenation (called
   flattening) is performed if and when a linear char array is requested. In
   general, ropes form a binary dag whose internal nodes are JSRope string
   headers with no associated char array and whose leaf nodes are linear
   strings.</p>
</blockquote>

<p>Details about the <a href="https://en.wikipedia.org/wiki/Rope_(data_structure)">the rope data structure</a> are available on Wikipedia.
Concetenation takes O(lgN) time where N is the number of concats in the rope so far.
As a result, to concat N times, the complexity is O( sum from 1 to N (lg N)) which is O(N lg N ) as explained in this <a href="https://stackoverflow.com/questions/38849052/time-complexity-with-log-in-loop">Stackoverflow article</a>.
It’s not as good as using a StringBuilder for really large data, which amoritzes to O(N).
However, for the number of concatenations that will work in the browser (2^27), the rope is good enough because behaves linearly until then.
If you plan to need more than that, at some point it will be better to use a builder.</p>

<h1 id="javascript-stringbulder">Javascript StringBulder</h1>

<p>I tried implementing my own StringBuilder for fun to see if I could improve upon the 10 seconds it takes in Firefox and failed.
My version of StringBuilder implemented in Javascript in Firefox took over 70 seconds to handle 2^27 concatenations.
Javascript provides a couple ways of creating strings directly from arrays.</p>

<p>The first I tried was <code class="language-plaintext highlighter-rouge">String.fromCharCode</code>.
This method looked like it would be faster; however, at 2^17 it fails with <code class="language-plaintext highlighter-rouge">Uncaught RangeError: Maximum call stack size exceeded</code>
because <code class="language-plaintext highlighter-rouge">String.fromCharCode</code> uses function parameter arguments.
As a result, when you use <code class="language-plaintext highlighter-rouge">...</code> array expansion or <code class="language-plaintext highlighter-rouge">Function.apply</code>, you blow up your stack.</p>

<p>In my second attempt, I tried using <a href="https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder">TextDecoder</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder">TextEncoder</a>.
In Firefox took over 70 seconds to handle 2^27 concatenations! As a result, you cannot implement a StringBuilder efficiently in Javascript yet.</p>

<p>I was able to improve the performance for 2^27 concatenations by using Rust’s String and connecting it to Javascript through WASM.
Rust’s String acts similarly to Java’s StringBuilder using an expanding buffer that amortizes each concat to be O(1) over all the concats.
Unfortunately, it only brought it down to 23 seconds, which is still worse than Javascript’s += and Array.join.</p>

<h1 id="discussion">Discussion</h1>
<p>Could Java implement a similar optimization to the JVM so that people who overlook this mistake aren’t hit with an O(N^2) but a O(NlgN) algorithm instead?</p>

<p>Are ropes good enough? At 2^24 to 2^27 we’re measuring the concatenations in seconds and the growth appears linear until that point even though asymptotically it is O(NlgN).
You could argue that’s good enough because that’s the memory limit of the browser.</p>

<p>Would a StringBuilder implemented in WASM perform significantly better than <code class="language-plaintext highlighter-rouge">+=</code> and <code class="language-plaintext highlighter-rouge">Array.join</code> if there was a sufficient amount of concatenations?
Unfortunately, I was limited to 2^27 concatenations before running out of memory.
If I was able to exceed that memory limit, I expect that WASM, and even my Javascript StringBuilder to eventually perform better due to the O(N) versus O(NlgN) complexity.</p>

<p>Finally, would we see a performance improvement if we implemented a StringBuilder in the javascript virtual machine instead of JSRope and rebuilt the browser?</p>

<h1 id="java-source">Java source</h1>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span> <span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
    <span class="kd">final</span> <span class="kt">int</span> <span class="n">base</span><span class="o">;</span>
    <span class="kd">final</span> <span class="kt">int</span> <span class="n">startPower</span><span class="o">;</span>
    <span class="kd">final</span> <span class="kt">int</span> <span class="n">concatPowerLimit</span><span class="o">;</span>
    <span class="kd">final</span> <span class="kt">int</span> <span class="n">powerLimit</span><span class="o">;</span>

    <span class="k">if</span><span class="o">(</span><span class="n">args</span><span class="o">.</span><span class="na">length</span> <span class="o">&gt;=</span> <span class="mi">4</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">base</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">args</span><span class="o">[</span><span class="mi">0</span><span class="o">]);</span>
        <span class="n">startPower</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">args</span><span class="o">[</span><span class="mi">1</span><span class="o">]);</span>
        <span class="n">concatPowerLimit</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">args</span><span class="o">[</span><span class="mi">2</span><span class="o">]);</span>
        <span class="n">powerLimit</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">args</span><span class="o">[</span><span class="mi">3</span><span class="o">]);</span>
    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
        <span class="n">base</span> <span class="o">=</span> <span class="mi">2</span><span class="o">;</span>
        <span class="n">startPower</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span>
        <span class="n">concatPowerLimit</span> <span class="o">=</span> <span class="mi">21</span><span class="o">;</span> <span class="c1">// at least 2 hours to compute the 22nd one</span>
        <span class="n">powerLimit</span> <span class="o">=</span> <span class="mi">27</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="k">for</span><span class="o">(</span><span class="kt">int</span> <span class="n">power</span> <span class="o">=</span> <span class="n">startPower</span><span class="o">;</span> <span class="n">power</span> <span class="o">&lt;=</span> <span class="mi">27</span><span class="o">;</span> <span class="n">power</span><span class="o">++)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">size</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span><span class="nc">Math</span><span class="o">.</span><span class="na">pow</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span> <span class="n">power</span><span class="o">);</span>
        <span class="n">runStringBuilderExperiment</span><span class="o">(</span><span class="n">base</span><span class="o">,</span> <span class="n">power</span><span class="o">,</span> <span class="n">size</span><span class="o">);</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">power</span> <span class="o">&lt;=</span> <span class="n">concatPowerLimit</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">runConcatExperiment</span><span class="o">(</span><span class="n">base</span><span class="o">,</span> <span class="n">power</span><span class="o">,</span> <span class="n">size</span><span class="o">);</span>
        <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">runConcatExperiment</span><span class="o">(</span><span class="kt">int</span> <span class="n">base</span><span class="o">,</span> <span class="kt">int</span> <span class="n">power</span><span class="o">,</span> <span class="kt">int</span> <span class="n">size</span><span class="o">)</span> <span class="o">{</span>
    <span class="nc">String</span> <span class="n">result</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span>
    <span class="kt">long</span> <span class="n">start</span> <span class="o">=</span> <span class="nc">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">();</span>
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">size</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
        <span class="n">result</span> <span class="o">+=</span> <span class="o">(</span><span class="n">i</span><span class="o">%</span><span class="mi">10</span><span class="o">);</span>
    <span class="o">}</span>
    <span class="kt">long</span> <span class="n">end</span> <span class="o">=</span> <span class="nc">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">();</span>
    <span class="kt">long</span> <span class="n">duration</span> <span class="o">=</span> <span class="n">end</span> <span class="o">-</span> <span class="n">start</span><span class="o">;</span>
    <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="nc">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s">"concat %d^%d %d %d %d"</span><span class="o">,</span> <span class="n">base</span><span class="o">,</span> <span class="n">power</span><span class="o">,</span> <span class="n">size</span><span class="o">,</span> <span class="n">result</span><span class="o">.</span><span class="na">length</span><span class="o">(),</span> <span class="n">duration</span><span class="o">));</span>
<span class="o">}</span>

<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">runStringBuilderExperiment</span><span class="o">(</span><span class="kt">int</span> <span class="n">base</span><span class="o">,</span> <span class="kt">int</span> <span class="n">power</span><span class="o">,</span> <span class="kt">int</span> <span class="n">size</span><span class="o">)</span> <span class="o">{</span>
    <span class="nc">StringBuilder</span> <span class="n">builder</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StringBuilder</span><span class="o">();</span>
    <span class="kt">long</span> <span class="n">start</span> <span class="o">=</span> <span class="nc">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">();</span>
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">size</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
        <span class="n">builder</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="n">i</span><span class="o">%</span><span class="mi">10</span><span class="o">);</span>
    <span class="o">}</span>
    <span class="nc">String</span> <span class="n">result</span> <span class="o">=</span> <span class="n">builder</span><span class="o">.</span><span class="na">toString</span><span class="o">();</span>
    <span class="kt">long</span> <span class="n">end</span> <span class="o">=</span> <span class="nc">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">();</span>
    <span class="kt">long</span> <span class="n">duration</span> <span class="o">=</span> <span class="n">end</span> <span class="o">-</span> <span class="n">start</span><span class="o">;</span>
    <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="nc">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s">"builder %d^%d %d %d %d"</span><span class="o">,</span> <span class="n">base</span><span class="o">,</span> <span class="n">power</span><span class="o">,</span> <span class="n">size</span><span class="o">,</span> <span class="n">result</span><span class="o">.</span><span class="na">length</span><span class="o">(),</span> <span class="n">duration</span><span class="o">));</span>
<span class="o">}</span>
</code></pre></div></div>

<h1 id="javascript-naive-concat-and-arrayjoin-source">Javascript Naive Concat and Array.join Source</h1>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">runConcatExperiment</span><span class="p">(</span><span class="nx">size</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="dl">""</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">start</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">getTime</span><span class="p">();</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">size</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">result</span> <span class="o">+=</span> <span class="p">(</span><span class="nx">i</span><span class="o">%</span><span class="mi">10</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="kd">var</span> <span class="nx">end</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">getTime</span><span class="p">();</span>
    <span class="kd">var</span> <span class="nx">duration</span> <span class="o">=</span> <span class="nx">end</span> <span class="o">-</span> <span class="nx">start</span><span class="p">;</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">concat %d %d %d</span><span class="dl">"</span><span class="p">,</span> <span class="nx">size</span><span class="p">,</span> <span class="nx">result</span><span class="p">.</span><span class="nx">length</span><span class="p">,</span> <span class="nx">duration</span><span class="p">);</span>
    <span class="k">return</span> <span class="nx">duration</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">runArrayJoinExperiment</span><span class="p">(</span><span class="nx">size</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">builder</span> <span class="o">=</span> <span class="p">[];</span>
    <span class="kd">var</span> <span class="nx">start</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">getTime</span><span class="p">();</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">size</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">builder</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">i</span><span class="o">%</span><span class="mi">10</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">builder</span><span class="p">.</span><span class="nx">join</span><span class="p">();</span>
    <span class="kd">var</span> <span class="nx">end</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">getTime</span><span class="p">();</span>
    <span class="kd">var</span> <span class="nx">duration</span> <span class="o">=</span> <span class="nx">end</span> <span class="o">-</span> <span class="nx">start</span><span class="p">;</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">concat %d %d %d</span><span class="dl">"</span><span class="p">,</span> <span class="nx">size</span><span class="p">,</span> <span class="nx">result</span><span class="p">.</span><span class="nx">length</span><span class="p">,</span> <span class="nx">duration</span><span class="p">);</span>
    <span class="k">return</span> <span class="nx">duration</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">addRow</span><span class="p">(</span><span class="nx">base</span><span class="p">,</span> <span class="nx">power</span><span class="p">,</span> <span class="nx">size</span><span class="p">,</span> <span class="nx">concatDuration</span><span class="p">,</span> <span class="nx">arrayJoinDuration</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">resultsTable</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">results</span><span class="dl">"</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">tableRow</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="dl">"</span><span class="s2">tr</span><span class="dl">"</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">powerCell</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="dl">"</span><span class="s2">td</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">powerCell</span><span class="p">.</span><span class="nx">innerText</span> <span class="o">=</span> <span class="nx">base</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">^</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">power</span><span class="p">;</span>
    <span class="nx">tableRow</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="nx">powerCell</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">sizeCell</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="dl">"</span><span class="s2">td</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">sizeCell</span><span class="p">.</span><span class="nx">innerText</span> <span class="o">=</span> <span class="nx">size</span><span class="p">;</span>
    <span class="nx">tableRow</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="nx">sizeCell</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">concatCell</span>  <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="dl">"</span><span class="s2">td</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">concatCell</span><span class="p">.</span><span class="nx">innerText</span> <span class="o">=</span> <span class="nx">concatDuration</span><span class="p">;</span>
    <span class="nx">tableRow</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="nx">concatCell</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">joinCell</span>  <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="dl">"</span><span class="s2">td</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">joinCell</span><span class="p">.</span><span class="nx">innerText</span> <span class="o">=</span> <span class="nx">arrayJoinDuration</span><span class="p">;</span>
    <span class="nx">tableRow</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="nx">joinCell</span><span class="p">);</span>
    <span class="nx">resultsTable</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">tableRow</span><span class="p">);</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">runExperiment</span><span class="p">()</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">baseInput</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">base</span><span class="dl">"</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">base</span> <span class="o">=</span> <span class="nx">baseInput</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">powerLimitInput</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">powerLimit</span><span class="dl">"</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">powerLimit</span> <span class="o">=</span> <span class="nx">powerLimitInput</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
    <span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">power</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">power</span> <span class="o">&lt;=</span> <span class="nx">powerLimit</span><span class="p">;</span> <span class="nx">power</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">var</span> <span class="nx">size</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">pow</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="nx">power</span><span class="p">);</span>
        <span class="kd">var</span> <span class="nx">concatDuration</span> <span class="o">=</span> <span class="nx">runConcatExperiment</span><span class="p">(</span><span class="nx">size</span><span class="p">);</span>
        <span class="kd">var</span> <span class="nx">arrayJoinDuration</span> <span class="o">=</span> <span class="nx">runArrayJoinExperiment</span><span class="p">(</span><span class="nx">size</span><span class="p">);</span>
        <span class="nx">addRow</span><span class="p">(</span><span class="nx">base</span><span class="p">,</span> <span class="nx">power</span><span class="p">,</span> <span class="nx">size</span><span class="p">,</span> <span class="nx">concatDuration</span><span class="p">,</span> <span class="nx">arrayJoinDuration</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h1 id="javascript-string-builder">Javascript String Builder</h1>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">StringBuilder</span><span class="p">()</span> <span class="p">{</span>

    <span class="c1">// cannot use String.fromCharCode due to</span>
    <span class="c1">// Uncaught RangeError: Maximum call stack size exceeded</span>
    <span class="c1">// so we are stuck with TextEncoder and TextDecoder</span>
    <span class="c1">// https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder</span>
    <span class="c1">// https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder</span>
    <span class="kd">let</span> <span class="nx">utf8Decoder</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">TextDecoder</span><span class="p">();</span>
    <span class="kd">let</span> <span class="nx">utf8Encoder</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">TextEncoder</span><span class="p">();</span>

    <span class="k">this</span><span class="p">.</span><span class="nx">bufferConsumed</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">capacity</span> <span class="o">=</span> <span class="mi">128</span><span class="p">;</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">buffer</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint8Array</span><span class="p">(</span><span class="mi">128</span><span class="p">);</span>

    <span class="k">this</span><span class="p">.</span><span class="nx">append</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">strToAdd</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// O(N) copy but ammortized to O(1) over all concats</span>
        <span class="kd">var</span> <span class="nx">encodedStr</span> <span class="o">=</span> <span class="nx">utf8Encoder</span><span class="p">.</span><span class="nx">encode</span><span class="p">(</span><span class="nx">strToAdd</span><span class="p">);</span>
        <span class="k">while</span> <span class="p">(</span><span class="nx">encodedStr</span><span class="p">.</span><span class="nx">length</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">bufferConsumed</span> <span class="o">&gt;</span> <span class="k">this</span><span class="p">.</span><span class="nx">capacity</span><span class="p">)</span> <span class="p">{</span>
            <span class="kd">var</span> <span class="nx">tmpBuffer</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">buffer</span><span class="p">;</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">buffer</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint8Array</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">capacity</span><span class="o">*</span><span class="mi">2</span><span class="p">);</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">capacity</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">capacity</span><span class="o">*</span><span class="mi">2</span><span class="p">;</span>
            <span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="k">this</span><span class="p">.</span><span class="nx">bufferConsumed</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">buffer</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">tmpBuffer</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="c1">// add the characters to the end</span>
        <span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">encodedStr</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">buffer</span><span class="p">[</span><span class="nx">i</span><span class="o">+</span><span class="k">this</span><span class="p">.</span><span class="nx">bufferConsumed</span><span class="p">]</span> <span class="o">=</span> <span class="nx">encodedStr</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">bufferConsumed</span> <span class="o">+=</span> <span class="nx">encodedStr</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span>

        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">this</span><span class="p">.</span><span class="nx">build</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nx">utf8Decoder</span><span class="p">.</span><span class="nx">decode</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">buffer</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">bufferConsumed</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h1 id="rust-wasm-string">Rust WASM String</h1>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">mod</span> <span class="n">utils</span><span class="p">;</span>

<span class="k">use</span> <span class="nn">wasm_bindgen</span><span class="p">::</span><span class="nn">prelude</span><span class="p">::</span><span class="o">*</span><span class="p">;</span>

<span class="c1">// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global</span>
<span class="c1">// allocator.</span>
<span class="nd">#[cfg(feature</span> <span class="nd">=</span> <span class="s">"wee_alloc"</span><span class="nd">)]</span>
<span class="nd">#[global_allocator]</span>
<span class="k">static</span> <span class="n">ALLOC</span><span class="p">:</span> <span class="nn">wee_alloc</span><span class="p">::</span><span class="n">WeeAlloc</span> <span class="o">=</span> <span class="nn">wee_alloc</span><span class="p">::</span><span class="nn">WeeAlloc</span><span class="p">::</span><span class="n">INIT</span><span class="p">;</span>

<span class="nd">#[wasm_bindgen]</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">RustStringBuilder</span> <span class="p">{</span>
    <span class="c1">// String push_str uses a vector internally</span>
    <span class="c1">// vector amortizes push to O(1) over many appends</span>
    <span class="n">internal</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span>
<span class="p">}</span>

<span class="nd">#[wasm_bindgen]</span>
<span class="k">impl</span> <span class="n">RustStringBuilder</span> <span class="p">{</span>

    <span class="nd">#[wasm_bindgen(constructor)]</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="n">RustStringBuilder</span> <span class="p">{</span>
        <span class="n">RustStringBuilder</span> <span class="p">{</span> <span class="n">internal</span><span class="p">:</span> <span class="nn">String</span><span class="p">::</span><span class="nf">from</span><span class="p">(</span><span class="s">""</span><span class="p">)</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">append</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">to_append</span><span class="p">:</span> <span class="nb">String</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.internal</span><span class="nf">.push_str</span><span class="p">(</span><span class="n">to_append</span><span class="nf">.as_str</span><span class="p">())</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">build</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">String</span>  <span class="p">{</span>
        <span class="nn">String</span><span class="p">::</span><span class="nf">from</span><span class="p">(</span><span class="k">self</span><span class="py">.internal</span><span class="nf">.as_str</span><span class="p">())</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name>joseph.mate</name></author><category term="Java" /><category term="Javascript" /><category term="StringBuilder" /><summary type="html"><![CDATA[Today I learned that Javascript does not need a StringBuilder for accumulating a large number of concatinations. As a Java programmer, that came as a shock to me. This article summarizes my exploration of this fact.]]></summary></entry><entry><title type="html">Deadlock: Who Owns the Lock?</title><link href="https://josephmate.github.io/2020-02-24-deadlock-who-owns-the-lock/" rel="alternate" type="text/html" title="Deadlock: Who Owns the Lock?" /><published>2020-02-24T18:40:00-05:00</published><updated>2020-02-24T18:40:00-05:00</updated><id>https://josephmate.github.io/deadlock-who-owns-the-lock</id><content type="html" xml:base="https://josephmate.github.io/2020-02-24-deadlock-who-owns-the-lock/"><![CDATA[<h1 id="what-i-learned">What I Learned:</h1>
<ol>
  <li>Locking a readlock, then locking the write lock on the same lock creates a deadlock.</li>
  <li>Deadlocks created using locks instead of monitors does not appear in thread dumps (like those created by kill -3 (linux) or Ctrl+Break (windows)).</li>
  <li>Keep digging and you’ll uncover a nasty incorrect assumption you’ve been making.</li>
  <li><code class="language-plaintext highlighter-rouge">-XX:+PrintConcurrentLocks</code> detects some deadlocks</li>
  <li><code class="language-plaintext highlighter-rouge">-XX:+PrintConcurrentLocks</code> does not print reentrant locks on stack traces</li>
  <li><code class="language-plaintext highlighter-rouge">-XX:+PrintConcurrentLocks</code> does not detect acquiring read then write lock in the same thread deadlock</li>
</ol>

<p>If this interests you read on!</p>

<h1 id="every-good-story-starts-with-a-difficult-bug">Every good story starts with a difficult bug</h1>
<p>Recently I stumbled up this bug where it appeared like my threads were deadlocked, but triggered a thread dump to stand out using <code class="language-plaintext highlighter-rouge">kill -3 $(pidof java)</code> or <code class="language-plaintext highlighter-rouge">Ctrl+Break</code> did not report any deadlocks. Normally when you have a dead lock you would see something like below at the end of the thread dump:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x000000001a1c2598 (object 0x00000000d57695f8, a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x000000000331b628 (object 0x00000000d5769608, a java.lang.Object),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
        at SimpleMonitorDeadlockMain$DeadlockRunnable.run(SimpleMonitorDeadlockMain.java:25)
        - waiting to lock &lt;0x00000000d57695f8&gt; (a java.lang.Object)
        - locked &lt;0x00000000d5769608&gt; (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:748)
"Thread-0":
        at SimpleMonitorDeadlockMain$DeadlockRunnable.run(SimpleMonitorDeadlockMain.java:25)
        - waiting to lock &lt;0x00000000d5769608&gt; (a java.lang.Object)
        - locked &lt;0x00000000d57695f8&gt; (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.
</code></pre></div></div>

<p>But in my bug, I was seeing something like</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"main" #1 prio=5 os_prio=0 tid=0x00000000030c3000 nid=0x4fb0 waiting on condition [0x0000000002f2e000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  &lt;0x00000000d5820098&gt; (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
	at java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.lock(ReentrantReadWriteLock.java:943)
	at ReadLockThenWriteLockMain.main(ReadLockThenWriteLockMain.java:11)
</code></pre></div></div>
<p>I couldn’t find who owned <code class="language-plaintext highlighter-rouge">0x00000000d5820098</code>.</p>

<p>Fortunately, with a little GoogleFu, I was able to find someone who encountered the same problem and learned a lot.
<a href="https://blogs.oracle.com/poonam/stackoverflowerror-and-threads-waiting-for-reentrantreadwritelock">StackOverflowError and threads waiting for ReentrantReadWriteLock by Poonam Parhar</a>.
Originally, I assumed that the read lock would be promoted to a write lock by stopping future readers and waiting for reader to leave.
So I put together a minimal reproducing program of the Oracle article to double check.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Starting!"</span><span class="o">);</span>
<span class="nc">ReadWriteLock</span> <span class="n">readWriteLock</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ReentrantReadWriteLock</span><span class="o">();</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Grabbing the read lock."</span><span class="o">);</span>
<span class="n">readWriteLock</span><span class="o">.</span><span class="na">readLock</span><span class="o">().</span><span class="na">lock</span><span class="o">();</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Grabbing the write lock."</span><span class="o">);</span>
<span class="n">readWriteLock</span><span class="o">.</span><span class="na">writeLock</span><span class="o">().</span><span class="na">lock</span><span class="o">();</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Releasing the write lock."</span><span class="o">);</span>
<span class="n">readWriteLock</span><span class="o">.</span><span class="na">writeLock</span><span class="o">().</span><span class="na">unlock</span><span class="o">();</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Releasing the read lock."</span><span class="o">);</span>
<span class="n">readWriteLock</span><span class="o">.</span><span class="na">readLock</span><span class="o">().</span><span class="na">unlock</span><span class="o">();</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Done!"</span><span class="o">);</span>
</code></pre></div></div>

<p>The above program produced the below standard out:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Starting!
Grabbing the read lock.
Grabbing the write lock.
</code></pre></div></div>
<p>The program makes no progress to the next println after that. It was deadlocked and the thread dump didn’t show who owned the thing the main thread was waiting for. That must have been my bug (it wasn’t)!</p>

<h1 id="the-grim-realization">The Grim Realization</h1>
<p>I wanted to share what I learned by putting together this article. The first thing I needed was a sample deadlock that showed reeantrant locks dead locking and the standard out it produced:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">DeadlockRunnable</span> <span class="kd">implements</span> <span class="nc">Runnable</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">Lock</span> <span class="n">lockToGrabFirst</span><span class="o">;</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">Lock</span> <span class="n">lockToGrabSecond</span><span class="o">;</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">CyclicBarrier</span> <span class="n">ensureBothThreadsGrabTheirLock</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nf">DeadlockRunnable</span><span class="o">(</span><span class="nc">CyclicBarrier</span> <span class="n">ensureBothThreadsGrabTheirLock</span><span class="o">,</span>
                            <span class="nc">Lock</span> <span class="n">lockToGrabFirst</span><span class="o">,</span>
                            <span class="nc">Lock</span> <span class="n">lockToGrabSecond</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">ensureBothThreadsGrabTheirLock</span> <span class="o">=</span> <span class="n">ensureBothThreadsGrabTheirLock</span><span class="o">;</span>
        <span class="k">this</span><span class="o">.</span><span class="na">lockToGrabFirst</span> <span class="o">=</span> <span class="n">lockToGrabFirst</span><span class="o">;</span>
        <span class="k">this</span><span class="o">.</span><span class="na">lockToGrabSecond</span> <span class="o">=</span> <span class="n">lockToGrabSecond</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">run</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">try</span> <span class="o">{</span>
            <span class="n">lockToGrabFirst</span><span class="o">.</span><span class="na">lock</span><span class="o">();</span>

            <span class="c1">// wait until thread2 reaches barrier before asking for the next lock</span>
            <span class="n">ensureBothThreadsGrabTheirLock</span><span class="o">.</span><span class="na">await</span><span class="o">();</span>

            <span class="n">lockToGrabSecond</span><span class="o">.</span><span class="na">lock</span><span class="o">();</span>
        <span class="o">}</span> <span class="k">catch</span><span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
        <span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
            <span class="n">lockToGrabSecond</span><span class="o">.</span><span class="na">unlock</span><span class="o">();</span>
            <span class="n">lockToGrabFirst</span><span class="o">.</span><span class="na">unlock</span><span class="o">();</span>
        <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">InterruptedException</span> <span class="o">{</span>
    <span class="nc">Lock</span> <span class="n">lock1</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ReentrantLock</span><span class="o">();</span>
    <span class="nc">Lock</span> <span class="n">lock2</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ReentrantLock</span><span class="o">();</span>
    <span class="nc">CyclicBarrier</span> <span class="n">ensureBothThreadsGrabTheirLock</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">CyclicBarrier</span><span class="o">(</span><span class="mi">2</span><span class="o">);</span>

    <span class="nc">Thread</span> <span class="n">thread1</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Thread</span><span class="o">(</span><span class="k">new</span> <span class="nc">DeadlockRunnable</span><span class="o">(</span><span class="n">ensureBothThreadsGrabTheirLock</span><span class="o">,</span> <span class="n">lock1</span><span class="o">,</span> <span class="n">lock2</span><span class="o">));</span>
    <span class="c1">// reverse the order in which the locks are grabbed</span>
    <span class="nc">Thread</span> <span class="n">thread2</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Thread</span><span class="o">(</span><span class="k">new</span> <span class="nc">DeadlockRunnable</span><span class="o">(</span><span class="n">ensureBothThreadsGrabTheirLock</span><span class="o">,</span> <span class="n">lock2</span><span class="o">,</span> <span class="n">lock1</span><span class="o">));</span>
    <span class="n">thread1</span><span class="o">.</span><span class="na">start</span><span class="o">();</span>
    <span class="n">thread2</span><span class="o">.</span><span class="na">start</span><span class="o">();</span>

    <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">print</span><span class="o">(</span><span class="s">"Waiting for thread1 to complete."</span><span class="o">);</span>
    <span class="n">thread1</span><span class="o">.</span><span class="na">join</span><span class="o">();</span>
    <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">print</span><span class="o">(</span><span class="s">"Waiting for thread2 to complete."</span><span class="o">);</span>
    <span class="n">thread2</span><span class="o">.</span><span class="na">join</span><span class="o">();</span>
    <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">print</span><span class="o">(</span><span class="s">"Done!"</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The above program produces the below standard out.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Waiting for thread1 to complete.
</code></pre></div></div>
<p>The program makes no progress to the next println after that. It was deadlocked.
But then I sent <code class="language-plaintext highlighter-rouge">kill -3</code> or <code class="language-plaintext highlighter-rouge">Crtl+Break</code> to get the thread dump and I saw a familiar issue:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"Thread-1" #12 prio=5 os_prio=0 tid=0x0000000019abc800 nid=0x748c waiting on condition [0x000000001a55f000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  &lt;0x00000000d581cbe0&gt; (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
	at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
	at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
	at SimpleReentrantDeadlockMain$DeadlockRunnable.run(SimpleReentrantDeadlockMain.java:27)
	at java.lang.Thread.run(Thread.java:748)


"Thread-0" #11 prio=5 os_prio=0 tid=0x0000000019aba000 nid=0x19a4 waiting on condition [0x000000001a45e000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  &lt;0x00000000d581cc10&gt; (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
	at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
	at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
	at SimpleReentrantDeadlockMain$DeadlockRunnable.run(SimpleReentrantDeadlockMain.java:27)
	at java.lang.Thread.run(Thread.java:748)
</code></pre></div></div>
<p>THE DUMP DOES NOT SHOW WHO OWNS WHAT IT’S WAITING FOR!!!
I thought it was because of a read then write lock, similar to the Oracle article, that caused the thread dump to not show who owns the lock.
That was not why.
The real reason was lock ownership is not shown by thread dumps.
“The default deadlock detection works with locks that are obtained using the synchronized keyword, as well as with locks that are obtained using the java.util.concurrent package. If the Java VM flag <code class="language-plaintext highlighter-rouge">-XX:+PrintConcurrentLocks</code> is set, then the stack trace also shows a list of lock owners.” <a href="https://docs.oracle.com/javase/7/docs/webnotes/tsg/TSG-VM/html/hangloop.html">Troubleshooting Hanging or Looping Processes</a>.
I’ll have to try with <code class="language-plaintext highlighter-rouge">-XX:+PrintConcurrentLocks</code>.</p>

<h1 id="-xxprintconcurrentlocks">-XX:+PrintConcurrentLocks</h1>

<p>I tried running my deadlock programs again, but this time with <code class="language-plaintext highlighter-rouge">-XX:+PrintConcurrentLocks</code>.</p>

<p>Now with the Reentrant locks kill -3, or crtl+break, and it still does not show lock owner in the stack trace:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s2">"Thread-1"</span> <span class="c">#11 prio=5 os_prio=0 tid=0x0000000019fb7000 nid=0x29cc waiting on condition [0x000000001a6cf000]</span>
   java.lang.Thread.State: WAITING <span class="o">(</span>parking<span class="o">)</span>
        at sun.misc.Unsafe.park<span class="o">(</span>Native Method<span class="o">)</span>
        - parking to <span class="nb">wait </span><span class="k">for</span>  &lt;0x00000000d576ade0&gt; <span class="o">(</span>a java.util.concurrent.locks.ReentrantLock<span class="nv">$NonfairSync</span><span class="o">)</span>
        at java.util.concurrent.locks.LockSupport.park<span class="o">(</span>LockSupport.java:175<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt<span class="o">(</span>AbstractQueuedSynchronizer.java:836<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued<span class="o">(</span>AbstractQueuedSynchronizer.java:870<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire<span class="o">(</span>AbstractQueuedSynchronizer.java:1199<span class="o">)</span>
        at java.util.concurrent.locks.ReentrantLock<span class="nv">$NonfairSync</span>.lock<span class="o">(</span>ReentrantLock.java:209<span class="o">)</span>
        at java.util.concurrent.locks.ReentrantLock.lock<span class="o">(</span>ReentrantLock.java:285<span class="o">)</span>
        at SimpleReentrantDeadlockMain<span class="nv">$DeadlockRunnable</span>.run<span class="o">(</span>SimpleReentrantDeadlockMain.java:27<span class="o">)</span>
        at java.lang.Thread.run<span class="o">(</span>Thread.java:748<span class="o">)</span>

<span class="s2">"Thread-0"</span> <span class="c">#10 prio=5 os_prio=0 tid=0x0000000019fb4000 nid=0x8344 waiting on condition [0x000000001a5cf000]</span>
   java.lang.Thread.State: WAITING <span class="o">(</span>parking<span class="o">)</span>
        at sun.misc.Unsafe.park<span class="o">(</span>Native Method<span class="o">)</span>
        - parking to <span class="nb">wait </span><span class="k">for</span>  &lt;0x00000000d576ae10&gt; <span class="o">(</span>a java.util.concurrent.locks.ReentrantLock<span class="nv">$NonfairSync</span><span class="o">)</span>
        at java.util.concurrent.locks.LockSupport.park<span class="o">(</span>LockSupport.java:175<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt<span class="o">(</span>AbstractQueuedSynchronizer.java:836<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued<span class="o">(</span>AbstractQueuedSynchronizer.java:870<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire<span class="o">(</span>AbstractQueuedSynchronizer.java:1199<span class="o">)</span>
        at java.util.concurrent.locks.ReentrantLock<span class="nv">$NonfairSync</span>.lock<span class="o">(</span>ReentrantLock.java:209<span class="o">)</span>
        at java.util.concurrent.locks.ReentrantLock.lock<span class="o">(</span>ReentrantLock.java:285<span class="o">)</span>
        at SimpleReentrantDeadlockMain<span class="nv">$DeadlockRunnable</span>.run<span class="o">(</span>SimpleReentrantDeadlockMain.java:27<span class="o">)</span>
        at java.lang.Thread.run<span class="o">(</span>Thread.java:748<span class="o">)</span>
</code></pre></div></div>

<p>However, now it detects the deadlock:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Found one Java-level deadlock:
<span class="o">=============================</span>
<span class="s2">"Thread-1"</span>:
  waiting <span class="k">for </span>ownable synchronizer 0x00000000d576ade0, <span class="o">(</span>a java.util.concurrent.locks.ReentrantLock<span class="nv">$NonfairSync</span><span class="o">)</span>,
  which is held by <span class="s2">"Thread-0"</span>
<span class="s2">"Thread-0"</span>:
  waiting <span class="k">for </span>ownable synchronizer 0x00000000d576ae10, <span class="o">(</span>a java.util.concurrent.locks.ReentrantLock<span class="nv">$NonfairSync</span><span class="o">)</span>,
  which is held by <span class="s2">"Thread-1"</span>

Java stack information <span class="k">for </span>the threads listed above:
<span class="o">===================================================</span>
<span class="s2">"Thread-1"</span>:
        at sun.misc.Unsafe.park<span class="o">(</span>Native Method<span class="o">)</span>
        - parking to <span class="nb">wait </span><span class="k">for</span>  &lt;0x00000000d576ade0&gt; <span class="o">(</span>a java.util.concurrent.locks.ReentrantLock<span class="nv">$NonfairSync</span><span class="o">)</span>
        at java.util.concurrent.locks.LockSupport.park<span class="o">(</span>LockSupport.java:175<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt<span class="o">(</span>AbstractQueuedSynchronizer.java:836<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued<span class="o">(</span>AbstractQueuedSynchronizer.java:870<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire<span class="o">(</span>AbstractQueuedSynchronizer.java:1199<span class="o">)</span>
        at java.util.concurrent.locks.ReentrantLock<span class="nv">$NonfairSync</span>.lock<span class="o">(</span>ReentrantLock.java:209<span class="o">)</span>
        at java.util.concurrent.locks.ReentrantLock.lock<span class="o">(</span>ReentrantLock.java:285<span class="o">)</span>
        at SimpleReentrantDeadlockMain<span class="nv">$DeadlockRunnable</span>.run<span class="o">(</span>SimpleReentrantDeadlockMain.java:27<span class="o">)</span>
        at java.lang.Thread.run<span class="o">(</span>Thread.java:748<span class="o">)</span>
<span class="s2">"Thread-0"</span>:
        at sun.misc.Unsafe.park<span class="o">(</span>Native Method<span class="o">)</span>
        - parking to <span class="nb">wait </span><span class="k">for</span>  &lt;0x00000000d576ae10&gt; <span class="o">(</span>a java.util.concurrent.locks.ReentrantLock<span class="nv">$NonfairSync</span><span class="o">)</span>
        at java.util.concurrent.locks.LockSupport.park<span class="o">(</span>LockSupport.java:175<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt<span class="o">(</span>AbstractQueuedSynchronizer.java:836<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued<span class="o">(</span>AbstractQueuedSynchronizer.java:870<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire<span class="o">(</span>AbstractQueuedSynchronizer.java:1199<span class="o">)</span>
        at java.util.concurrent.locks.ReentrantLock<span class="nv">$NonfairSync</span>.lock<span class="o">(</span>ReentrantLock.java:209<span class="o">)</span>
        at java.util.concurrent.locks.ReentrantLock.lock<span class="o">(</span>ReentrantLock.java:285<span class="o">)</span>
        at SimpleReentrantDeadlockMain<span class="nv">$DeadlockRunnable</span>.run<span class="o">(</span>SimpleReentrantDeadlockMain.java:27<span class="o">)</span>
        at java.lang.Thread.run<span class="o">(</span>Thread.java:748<span class="o">)</span>

Found 1 deadlock.
</code></pre></div></div>

<p>Same thing happens with acquiring the read then write lock in the same thread, the lock ownership is not shown in the stacktrace.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s2">"main"</span> <span class="c">#1 prio=5 os_prio=0 tid=0x0000000002461000 nid=0x4f10 waiting on condition [0x00000000023ff000]</span>
   java.lang.Thread.State: WAITING <span class="o">(</span>parking<span class="o">)</span>
        at sun.misc.Unsafe.park<span class="o">(</span>Native Method<span class="o">)</span>
        - parking to <span class="nb">wait </span><span class="k">for</span>  &lt;0x00000000d576bc70&gt; <span class="o">(</span>a java.util.concurrent.locks.ReentrantReadWriteLock<span class="nv">$NonfairSync</span><span class="o">)</span>
        at java.util.concurrent.locks.LockSupport.park<span class="o">(</span>LockSupport.java:175<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt<span class="o">(</span>AbstractQueuedSynchronizer.java:836<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued<span class="o">(</span>AbstractQueuedSynchronizer.java:870<span class="o">)</span>
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire<span class="o">(</span>AbstractQueuedSynchronizer.java:1199<span class="o">)</span>
        at java.util.concurrent.locks.ReentrantReadWriteLock<span class="nv">$WriteLock</span>.lock<span class="o">(</span>ReentrantReadWriteLock.java:943<span class="o">)</span>
        at ReadLockThenWriteLockMain.main<span class="o">(</span>ReadLockThenWriteLockMain.java:11<span class="o">)</span>

   Locked ownable synchronizers:
        - None
</code></pre></div></div>

<p>Even worse, the deadlock wasn’t detected!</p>

<h1 id="sample-code">Sample Code</h1>
<p>If you want to try it out, check the sample code I saved to <a href="https://github.com/josephmate/JavaDeadlocks">my JavaDeadlock github repository</a>.</p>]]></content><author><name>joseph.mate</name></author><category term="Java" /><category term="Deadlock" /><summary type="html"><![CDATA[What I Learned: Locking a readlock, then locking the write lock on the same lock creates a deadlock. Deadlocks created using locks instead of monitors does not appear in thread dumps (like those created by kill -3 (linux) or Ctrl+Break (windows)). Keep digging and you’ll uncover a nasty incorrect assumption you’ve been making. -XX:+PrintConcurrentLocks detects some deadlocks -XX:+PrintConcurrentLocks does not print reentrant locks on stack traces -XX:+PrintConcurrentLocks does not detect acquiring read then write lock in the same thread deadlock]]></summary></entry><entry><title type="html">Fix a Double Clicking Logitech M100 Mouse</title><link href="https://josephmate.github.io/2020-02-24-fix-double-clicking-mouse-logitech-m100/" rel="alternate" type="text/html" title="Fix a Double Clicking Logitech M100 Mouse" /><published>2020-02-24T18:40:00-05:00</published><updated>2020-02-24T18:40:00-05:00</updated><id>https://josephmate.github.io/fix-double-clicking-mouse-logitech-m100</id><content type="html" xml:base="https://josephmate.github.io/2020-02-24-fix-double-clicking-mouse-logitech-m100/"><![CDATA[<p>My $15 Logitech M100 mouse has served me well for at least two years.
It’s been so long that I can’t remember when I got it. 
It’s suffered so much abuse you can no longer make out the Logitech logo on the bottom.
This is the second time it started double clicking.
The first time I was able to fix it by opening it up and blowing compressed air at it.
If you’re experiencing double click, you might want to try blowing compressed air on it.
However, this time it didn’t work.
After some googling, I suspected it might have something to do with the switch.
There are some tutorials online on how to fix it, but they didn’t go into enough details.
The two areas I wish there was more info on: opening the switch and how to bend the metal.
I put together these instructions to help out with extra detail on those two steps.</p>

<p><img src="/assets/2020-06-09_fix_mouse/01-my-mouse.jpg" alt="Image of my mouse" /></p>

<h1 id="2-opening-the-mouse">2. Opening the Mouse</h1>

<p>To open the mouse, there’s a Philip’s screw on the bottom.
After unscrewing it, the top will come off easily.
I highlighted the left click switch that was double clicking:
<img src="/assets/2020-06-09_fix_mouse/02-opened-screw-removed.jpg" alt="Image of mouse with bottom screw removed and top removed" /></p>

<h1 id="3-opening-the-switch">3. Opening the Switch</h1>
<p>The M100 Logitech mouse uses two Kailh 0817YA or 0B17YA switches for the left and right buttons.
I had trouble reading the serial number even with my glasses on.
The switch has two clips on the longer sides holding it place.
You want it to be closed tight to prevent dust and oil from your fingers from getting inside.
Any foreign objects can prevent a clean connection when you press your mouse button.</p>

<p>I got a small flat head screw driver right under  the clips (highlighted in green), and pried it open.
I scraped at the opening until my flat head was able to fit in the small opening of the clip.
Do not go underneath the switch, or you’ll snap the switch off the board.
Warning: You will likely damage the clip like I did!
Fortunately, I was going to throw out the mouse, so I didn’t care.
<img src="/assets/2020-06-09_fix_mouse/03-how-how-to-open-switch.jpg" alt="How to open the switch" /></p>

<h1 id="4-success-but-be-careful">4. Success but Be Careful</h1>
<p>After opening be very careful.
There is a small fat T shaped piece that will come loose.
DO NOT LOSE IT!
That’s the piece that the top of the mouse presses to bend the metal to click.
<img src="/assets/2020-06-09_fix_mouse/04-success-but-careful.png" alt="Piece you can lose. Be careful!" /></p>

<p>Notice that my clips are damage; fortunately, they still were able to lock back on to the switch when I put them back.
<img src="/assets/2020-06-09_fix_mouse/05-some-damage.jpg" alt="Some damage from prying open" /></p>

<h1 id="5-fixing-the-switch">5. Fixing the Switch</h1>
<p>This is what the switch looks from above.
<img src="/assets/2020-06-09_fix_mouse/06-opened-from-above.jpg" alt="Switch from above" /></p>

<p>Below is what the switch looks like from the side.
WARNING: after you take out the metal, it will be incredibly tedious to place it back.
At first I thought I needed to bend it more, like in I’ve drawn next to the switch labeled in ‘red’ with old.
That didn’t work.
After putting it back together pressing the button didn’t make a clicking noise anymore and it would still double click on it’s own.</p>

<p>So I took it apart again and tried to flatten the curve as drew next to the green ‘new’.
After flattening the metal curve, it was so hard to put back.
My strategy was to line up the curve part with where it’s supposed to go.
Then try to lever the back part of the metal back to were it was with a flat screw driver.
You can press with your finger to simulate a click and the top of the metal should move without vibrating.</p>

<p>When putting the switch cover back, to prevent the fat T piece from falling out I flipped my board and switch cover upside down.
With the switch upside down, the fat T piece won’t fall out.
With both the circuit board and the switch cover flipped, I placed the switch cover back.</p>

<p><img src="/assets/2020-06-09_fix_mouse/07-opened-from-the-side.jpg" alt="Switch from the side and how to fix" /></p>

<p>After putting it back together and testing it out, my mouse stopped double clicking!
I guess over millions of clicks, I caused the ‘u’ to become really thin or tall and lose it’s spring.
When pressing it without enough spring, it allows the end piece that closes the circuit to vibrate.
The vibrations are what cause the double click.
By flattening or fattening the u shape and putting it back, you make it springier, preventing the vibrations.
Now with it fixed, I hope that I can keep using it for 2 more years!</p>]]></content><author><name>joseph.mate</name></author><category term="Mouse" /><category term="Electronics" /><category term="Repair" /><summary type="html"><![CDATA[My $15 Logitech M100 mouse has served me well for at least two years. It’s been so long that I can’t remember when I got it. It’s suffered so much abuse you can no longer make out the Logitech logo on the bottom. This is the second time it started double clicking. The first time I was able to fix it by opening it up and blowing compressed air at it. If you’re experiencing double click, you might want to try blowing compressed air on it. However, this time it didn’t work. After some googling, I suspected it might have something to do with the switch. There are some tutorials online on how to fix it, but they didn’t go into enough details. The two areas I wish there was more info on: opening the switch and how to bend the metal. I put together these instructions to help out with extra detail on those two steps.]]></summary></entry><entry><title type="html">Fixing a Mini Cinema Lightbox</title><link href="https://josephmate.github.io/2019-12-24-fixing-mini-cinema-lightbox/" rel="alternate" type="text/html" title="Fixing a Mini Cinema Lightbox" /><published>2019-12-24T12:40:00-05:00</published><updated>2019-12-24T12:40:00-05:00</updated><id>https://josephmate.github.io/fixing-mini-cinema-lightbox</id><content type="html" xml:base="https://josephmate.github.io/2019-12-24-fixing-mini-cinema-lightbox/"><![CDATA[<p>Instead of throwing away something, you should try to fix it, because the root cause might be simple to fix. 
I recently attended AWS Summit 2019 and VMWare kindly gave away these cool Mini Cinema Lightboxes! They are great decorations for a wedding or dinner party.</p>

<p><img src="/assets/2019-12-24-fix-mini-cinema-lightbox/01-intro.jpg" alt="Mini Cinema Lightbox" /></p>

<p>Unfortunately, when I put in the batteries and flipped the switch, the light would not come on. I popped the batteries into another electronic to double check that the batteries were fine.
I considered throwing away the lightbox since I got it for free and I thought the LED might be broken.
I decided not to because that’s incredibly wasteful and thought it might be something simple.
I took at crack at trying to fix it.</p>

<p>The hardest part was opening it up without breaking the plastic.
There’s no diagrams available for what’s inside so I was scared if I used too much force, one of the pieces would snap.
After some fidgetting, I noticed that the top and bottom bars need to come off by pushing parallel to the lit surface.
<img src="/assets/2019-12-24-fix-mini-cinema-lightbox/02-opening-lightbox.jpg" alt="Opening the Lightbox" /></p>

<p>After opening up the lightbox, the root cause was obvious:
<img src="/assets/2019-12-24-fix-mini-cinema-lightbox/03-obvious-issue.jpg" alt="Obvious Issue" />
The wire was not connected to the casing that held the batteries. Maybe at some stage during delivery the box was knocked hard enough for the soldered wire to come loose.</p>

<p>I reconnected the wire to the casing:
<img src="/assets/2019-12-24-fix-mini-cinema-lightbox/04-fixed.jpg" alt="Fixed" /></p>

<p>That fixed the issue:
<img src="/assets/2019-12-24-fix-mini-cinema-lightbox/05-fixed.jpg" alt="Fixed" /></p>

<p><img src="/assets/2019-12-24-fix-mini-cinema-lightbox/06-fixed.jpg" alt="Fixed" /></p>

<p>Lesson learned is that you should not assume a root cause until you’ve done enough investigation. Always try to open your broken device and fix it before throwing it out.</p>]]></content><author><name>joseph.mate</name></author><category term="Electronics" /><summary type="html"><![CDATA[Instead of throwing away something, you should try to fix it, because the root cause might be simple to fix. I recently attended AWS Summit 2019 and VMWare kindly gave away these cool Mini Cinema Lightboxes! They are great decorations for a wedding or dinner party.]]></summary></entry><entry><title type="html">Unit Testing Common Requirements</title><link href="https://josephmate.github.io/2016-08-28-unit-testing-common-requirements/" rel="alternate" type="text/html" title="Unit Testing Common Requirements" /><published>2016-08-28T20:25:00-04:00</published><updated>2016-08-28T20:25:00-04:00</updated><id>https://josephmate.github.io/unit-testing-common-requirements</id><content type="html" xml:base="https://josephmate.github.io/2016-08-28-unit-testing-common-requirements/"><![CDATA[<p>Suppose you wanted to unit test java.util.Map. How would you verify each implementation? Take a quick look at the <a href="https://docs.oracle.com/javase/7/docs/api/java/util/Map.html">Map javadoc</a>, and you’ll find 20 implementing classes. Each Map implementation has common unit tests for requirements that you want to avoid copying. In this post I illustrate two techniques you can use for testing common requirements over implementations by testing my simplified version of java.util.Map.</p>

<p>I also encountered a similar problem when taking the Coursera Scala Parallel Programming course. The course’s assignments required sequential and parallel implementations. I noticed I ended up copying and pasting my tests of the sequential implementation to the parallel one. I came up with these solutions to de-duplicate the code.</p>
<h1>Introduction to Example</h1>
<p>In this example we implement a simplified Map interface with three methods, get, put, and getKeys:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">interface</span> <span class="nc">Map</span><span class="o">&lt;</span><span class="no">K</span><span class="o">,</span><span class="no">V</span><span class="o">&gt;</span>  <span class="o">{</span>
	<span class="kt">void</span> <span class="nf">put</span><span class="o">(</span><span class="no">K</span> <span class="n">key</span><span class="o">,</span> <span class="no">V</span> <span class="n">value</span><span class="o">);</span>
	<span class="no">V</span> <span class="nf">get</span><span class="o">(</span><span class="no">K</span> <span class="n">key</span><span class="o">);</span>
	<span class="nc">List</span> <span class="nf">getKeys</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>

<p>We provide two implementations of the interface. InefficientMap uses two ArrayLists to store the keys and values and SortedMap which guarantees that getKeys() returns the keys in sorted order. The implementations are purposely naive because the focus of this article is the testing aspect, not performance.</p>
<h1>Method 1: Abstract Class</h1>
<p>Abstract classes can be used to test the common requirements of differing implementations. This method provides the least duplicated code. You have all the common test cases in the base class which makes use of a factory method for generating the implementation.</p>

<p>To apply the inheritance you follow these steps:</p>
<ol>
	<li>Create an abstract class for the common unit tests</li>
	<li>Add an abstract method that expects the extender provide a new instance the real implementation</li>
	<li>Add @Tests the verify the requirements of the interface</li>
	<li>Create a unit test class for each implementation and extend from the abstract unit test class</li>
	<li>Provide the real implementation expected by the abstract method</li>
	<li>Add any additional @Tests that test requirements specific to the implementation</li>
</ol>
<h2>Step 1 and 2: Creating the Abstract Class</h2>
<p>You create an abstract class with an abstract factory method for returning the real implementation.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">InheritingMapTest</span> <span class="o">{</span>
	<span class="n">protect</span> <span class="kd">abstract</span> <span class="nc">Map</span><span class="o">&lt;</span><span class="no">K</span><span class="o">,</span><span class="no">V</span><span class="o">&gt;</span> <span class="nf">makeMap</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>
<h2>Step 3: Add @Tests</h2>
<p>In the abstract unit test class, we include requirements that are common to all maps. The tests make use of the factory method for getting an instance of the implementation.</p>

<p>Here we look at only one of the many test cases for the Map interface. The factory provides us with a mechanism for obtaining a new instance of the implementation.</p>

<p>Getting the value using a key that was replaced is should return the most recent value.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">testValueReplaced</span><span class="o">()</span> <span class="o">{</span>
	<span class="nc">Map</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">map</span> <span class="o">=</span> <span class="n">makeMap</span><span class="o">();</span>
	<span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">10</span><span class="o">);</span>
	<span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">12</span><span class="o">);</span>
	<span class="n">assertEquals</span><span class="o">(</span><span class="nc">Integer</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="mi">12</span><span class="o">),</span> <span class="n">map</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="mi">0</span><span class="o">));</span>
<span class="o">}</span>
</code></pre></div></div>
<h2>Step 4 and 5: Create a Unit Test Class for each Implementation</h2>
<p>Now for each implementation we extend from the abstract class and implement the factory method.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">InheritingSortedMapTest</span> <span class="kd">extends</span> <span class="nc">InheritingMapTest</span> <span class="o">{</span>
	<span class="kd">protected</span> <span class="nc">Map</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="nf">makeMap</span><span class="o">()</span> <span class="o">{</span>
		<span class="k">return</span> <span class="k">new</span> <span class="nc">SortedMap</span><span class="o">&lt;&gt;(</span><span class="nc">IntComparator</span><span class="o">.</span><span class="na">intComparator</span><span class="o">);</span>
	<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h2>Step 6: Add Additional Tests of Uncommon Requirements to Subclass</h2>
<p>The sorted map comes with the additional requirement that the getKeys() method returns the keys in sorted order. We add tests of this new requirement into the subclass.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">testKeysSorted</span><span class="o">()</span> <span class="o">{</span>
	<span class="nc">SortedMap</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">SortedMap</span><span class="o">&lt;&gt;(</span><span class="nc">IntComparator</span><span class="o">.</span><span class="na">intComparator</span><span class="o">);</span>
	<span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span><span class="mi">12</span><span class="o">);</span>
	<span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span><span class="mi">11</span><span class="o">);</span>
	<span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="mi">3</span><span class="o">,</span><span class="mi">13</span><span class="o">);</span>
	<span class="nc">List</span> <span class="n">keys</span> <span class="o">=</span> <span class="n">map</span><span class="o">.</span><span class="na">getKeys</span><span class="o">();</span>
	<span class="k">for</span><span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span> <span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
		<span class="n">assertEquals</span><span class="o">(</span><span class="nc">Integer</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="o">),</span><span class="n">keys</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">i</span><span class="o">));</span>
	<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h1>Method 2: Composition</h1>
<p>An alternative to this pattern is to include all the tests in a helper class and have each unit test call the testAll() method. The problem with this solution is that you end up having a method which calls all your test methods which duplicates some code. More importantly, it makes it more difficult to figure out which test failed because you have to inspect the stack trace instead of click on the failed test in an IDE like eclipse.</p>
<ol>
	<li>Create a factory interface</li>
	<li>Create class containing that accepts the factory in the constructor</li>
	<li>Add tests the verify the requirements of the interface</li>
	<li>Call each test method from a public 'testAll()' method</li>
	<li>Create a unit test class for each implementation that creates and instance of the test class</li>
	<li>Provide an implementation of the factory to the test class</li>
	<li>Add any additional @Tests that test requirements specific to the implementation</li>
</ol>
<h2>Step 1 and 2: Create the Factory and Test Class</h2>
<p>The ‘Testing Class’ has a Factory for creating new instances of the implementation when it needs it.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">CompositionMapTest</span> <span class="o">{</span>
	<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">MapFactory</span> <span class="o">{</span>
		<span class="cm">/**
		 * Return a new instance of your implementation of Map&lt;&gt;;
		 */</span>
		<span class="nc">Map</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="nf">make</span><span class="o">()</span> <span class="o">;</span>
	<span class="o">}</span>

	<span class="kd">private</span> <span class="nc">MapFactory</span> <span class="n">mapFactory</span><span class="o">;</span>

	<span class="kd">public</span> <span class="nf">CompositionMapTest</span><span class="o">(</span><span class="nc">MapFactory</span> <span class="n">mapFactory</span><span class="o">)</span> <span class="o">{</span>
		<span class="k">this</span><span class="o">.</span><span class="na">mapFactory</span> <span class="o">=</span> <span class="n">mapFactory</span><span class="o">;</span>
	<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h2>Step 3 and 4: Add Tests</h2>
<p>We make use of the factory to create an instance of the implementation and verify the object matches the specification.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kt">void</span> <span class="nf">testValueReplaced</span><span class="o">()</span> <span class="o">{</span>
	<span class="nc">Map</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">map</span> <span class="o">=</span> <span class="n">mapFactory</span><span class="o">.</span><span class="na">make</span><span class="o">();</span>
	<span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">10</span><span class="o">);</span>
	<span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">12</span><span class="o">);</span>
	<span class="n">assertEquals</span><span class="o">(</span><span class="nc">Integer</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="mi">12</span><span class="o">),</span> <span class="n">map</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="mi">0</span><span class="o">));</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The ‘Testing Class’ invokes all the test methods in a “testAll()” method which the real test classes will call.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">testAll</span><span class="o">()</span> <span class="o">{</span>
	<span class="o">...</span>
	<span class="n">testValueReplaced</span><span class="o">();</span>
	<span class="o">...</span>
<span class="o">}</span>
</code></pre></div></div>

<h2>Step 5 and 6: Create a class for each implementation</h2>
<p>To reuse the existing tests of the ‘Test Class’ we create an instance of it, providing it with a Factory for creating implementations. We invoke the test class’s “testAll()” method to check our implementation.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">CompositionSortedMapTest</span> <span class="o">{</span>
	<span class="nd">@Test</span>
	<span class="kd">public</span> <span class="kt">void</span> <span class="nf">testBasicRequirements</span><span class="o">()</span> <span class="o">{</span>
		<span class="nc">CompositionMapTest</span> <span class="n">basicTests</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">CompositionMapTest</span><span class="o">(</span>
			<span class="k">new</span> <span class="nc">CompositionMapTest</span><span class="o">.</span><span class="na">MapFactory</span><span class="o">()</span> <span class="o">{</span>
				<span class="kd">public</span> <span class="nc">Map</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="nf">make</span><span class="o">()</span> <span class="o">{</span>
					<span class="k">return</span> <span class="k">new</span> <span class="nc">SortedMap</span><span class="o">&lt;&gt;(</span><span class="nc">IntComparator</span><span class="o">.</span><span class="na">intComparator</span><span class="o">);</span>
				<span class="o">}</span>
			<span class="o">});</span>
		<span class="n">basicTests</span><span class="o">.</span><span class="na">testAll</span><span class="o">();</span>
	<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h2>Step 7: Add any additional tests for uncommon requirements</h2>
<p>We write tests as we would normally for requirements that are not common to all Maps.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">testKeysSorted</span><span class="o">()</span> <span class="o">{</span>
	<span class="nc">SortedMap</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">SortedMap</span><span class="o">&lt;&gt;(</span><span class="nc">IntComparator</span><span class="o">.</span><span class="na">intComparator</span><span class="o">);</span>
	<span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span><span class="mi">12</span><span class="o">);</span>
	<span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span><span class="mi">11</span><span class="o">);</span>
	<span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="mi">3</span><span class="o">,</span><span class="mi">13</span><span class="o">);</span>
	<span class="nc">List</span> <span class="n">keys</span> <span class="o">=</span> <span class="n">map</span><span class="o">.</span><span class="na">getKeys</span><span class="o">();</span>
	<span class="k">for</span><span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span> <span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
		<span class="n">assertEquals</span><span class="o">(</span><span class="nc">Integer</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="o">),</span><span class="n">keys</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">i</span><span class="o">));</span>
	<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h1>Conclusion</h1>
<p>If you notice you’re copying and pasting unit test code for common requirements, consider one of these two techniques. However, these techniques are only guides because you will encounter cases that do not fit cleanly. As an exercise for the reader: how would you extend these techniques to apply to java.util.WeakHashMap? If you want to have a go I’ve made the source available on <a href="https://github.com/josephmate/inheriting_unit_tests">my github</a>.</p>]]></content><author><name>matejoseph</name></author><category term="Java" /><category term="java" /><category term="Programming" /><category term="Unit Testing" /><summary type="html"><![CDATA[Suppose you wanted to unit test java.util.Map. How would you verify each implementation? Take a quick look at the Map javadoc, and you’ll find 20 implementing classes. Each Map implementation has common unit tests for requirements that you want to avoid copying. In this post I illustrate two techniques you can use for testing common requirements over implementations by testing my simplified version of java.util.Map.]]></summary></entry></feed>