Skip to main content

Hashtable in Java

Hashtable : Deep Deep Explanation

Hashtable is one of the oldest collection classes in the Java ecosystem, dating back to JDK 1.0. Found in the java.util package, it is a legacy data structure that maps keys to values, very similar to a HashMap. But it possesses one critical, defining difference: It is fully synchronized (thread-safe).

Hashtable<Integer, String> table = new Hashtable<>();

table.put(101, "A");
table.put(102, "B");

System.out.println(table);
// Output: {102=B, 101=A} (No guaranteed order)

1. Internal Architecture & Node Structure

Like HashMap, Hashtable uses a Hash Table internally. This means it relies on an array of "buckets," and each bucket handles collisions by forming a linked list of nodes.

Hierarchy: ObjectDictionary (Legacy) → Hashtable.

The Node Structure

private static class Entry<K,V> { final int hash; final K key; V value; Entry<K,V> next; }

Every key-value pair is wrapped in this Entry object. It holds the cached hash, the key, the value, and a next pointer to handle separate chaining (collisions).


2. Backend Working Step-by-Step: put() & get()

Let's trace the exact backend flow when you run: table.put(15, "Java");

  • STEP 1 — Hash Calculation: Java triggers key.hashCode(). For an integer like 15, the hash is exactly 15.
  • STEP 2 — Bucket Index Math: To map the hash to a specific array bucket, Java uses a slightly different formula than HashMap to ensure positive integers:

    $$ \text{index} = (\text{hash} \ \& \ \text{0x7FFFFFFF}) \pmod{\text{table.length}} $$

    If the table length is 11, then 15 % 11 = 4. The entry maps to bucket 4.
  • STEP 3 — Insert Node: An Entry[15, Java] is physically placed inside bucket 4.

The Golden Rule of equals() & hashCode()

If you use a custom object (like a Student class) as a key, you MUST override hashCode() and equals(). Why? Because the default Object methods compare memory addresses. If you insert a value with new Student(1), and later try to retrieve it using a separate new Student(1), the memory addresses won't match, and Hashtable will return null.


3. Synchronization: The Ultimate Bottleneck

The single most important concept regarding Hashtable is its synchronization. Every core method in the class is marked with the synchronized keyword:

public synchronized V put(K key, V value) { ... }

This means Java enforces an Object Monitor Lock on the entire Hashtable instance.

[ THE HASHTABLE LOCK ] Thread 1 → Executing put() → LOCK ACQUIRED ✅ Thread 2 → Wants to get() → WAITING ⏳ Thread 3 → Wants to put() → WAITING ⏳ (When Thread 1 finishes, the lock is released, and Thread 2 may enter)

Why does this make Hashtable extremely slow?
Because it suffers from severe Thread Contention. Even if Thread 1 is updating bucket 2, and Thread 2 just wants to read data from bucket 8, Thread 2 is completely blocked. The entire data structure freezes for a single operation.


4. Resizing, Rehashing & Null Rules

Like all hash tables, when the structure gets too full, performance degrades. To fix this, Java automatically resizes it.

  • Load Factor: Defaults to 0.75.
  • Threshold calculation: Capacity × Load Factor. (e.g., $11 \times 0.75 = 8$). At the 8th insertion, the table resizes.
  • The Resize Formula: Unlike HashMap which perfectly doubles, Hashtable uses: $ (\text{oldCapacity} \times 2) + 1 $. (e.g., 11 becomes 23).
  • Rehashing: A new, larger array is created. Every single existing node is recalculated and moved. This is a massively expensive operation.

The Null Handling Crash

Hashtable absolutely DOES NOT allow null keys or null values.

table.put(null, "A"); // Throws NullPointerException!

Why? Because internally, the very first step in put() is to execute key.hashCode(). Invoking a method on a null reference immediately triggers a hard NPE crash.


5. Hashtable vs. The Modern Alternatives

Modern Java architectures rarely use Hashtable. Here is why it was replaced:

Feature HashMap (Fast) Hashtable (Legacy)
Thread-Safe No Yes
Speed Very Fast Slow (Bottlenecked)
Null Keys 1 Allowed Not Allowed (NPE)
Null Values Multiple Allowed Not Allowed (NPE)
Feature ConcurrentHashMap (Modern Solution) Hashtable (Legacy Solution)
Locking Strategy Locks only individual buckets (Node level) Locks the entire Object
Read Operations Fully concurrent (No locking needed) Blocked while writing is happening
Performance in Multi-threading Extremely High Extremely Poor

The Real-Life Analogy & Summary

Think of a Hashtable like a giant room full of apartment lockers protected by a single, highly strict security guard.

  • Safe? Yes. The guard only allows exactly ONE person inside the entire room at a time. No one will ever bump into each other.
  • Fast? Absolutely not. If you want to check Locker #5, and someone else is putting a package in Locker #99, you must wait outside in the rain until they are completely finished.

Why does it still exist? Purely for backward compatibility with ancient Java codebases (JDK 1.0/1.1) and legacy APIs. For any modern application requiring thread safety, you should immediately reach for ConcurrentHashMap instead.

Comments

Popular posts from this blog

How I Got Selected in MNC

Virtusa Sometimes success does not come from having the best coding skills or the perfect roadmap. Sometimes it comes from simply refusing to quit. This is the honest story of how I transitioned from a confused, rejected fresher to getting selected as an Associate Engineer at Virtusa. The Beginning: Confused About My Future After completing my graduation, I stared blankly at my career options. Like many freshers, I lacked a clear direction. Should I join a Java course? Should I prepare on my own? Should I just wait for campus placement opportunities? One day, I called my friend Chetan. He suggested I join Naresh i Technologies and start learning Java seriously. Still unsure of my path, I told him I needed time to think about it. A couple of days later, my phone buzzed with a WhatsApp message offering a job opportunity. They asked me to come for the next round of the recruitment process. Excitement completely took over. I packed my bags, traveled to th...

Spring Boot Introduction

Spring Boot Introduction: Architecture, Dependencies, and Embedded Servers Modern enterprise applications demand rapid development, frictionless deployment, and absolute minimal configuration. Before Spring Boot arrived, developers utilizing the Spring Framework wasted immense amounts of time configuring XML files, managing clashing dependencies, setting up clunky application servers, and stitching various Spring modules together manually. To eliminate these bottlenecks, Pivotal introduced Spring Boot . Built entirely on top of the traditional Spring Framework, Spring Boot is an "opinionated" framework. It aggressively simplifies application development by injecting auto-configuration, packaging starter dependencies, and embedding web servers directly into your application. This allows backend developers to focus entirely on building business logic rather than wrestling with infrastructure setup. What is Spring Boot? Spring Boot is a powerful extens...

Strings in C

C Programming: Working with Strings Unlike modern programming languages like Python or Java, C does not possess a dedicated "String" data type. Instead, C treats a string as a simple 1D array of characters. Real-life example: Think of a freight train. The train does not exist as one solid object; it consists of individual boxcars linked together. Similarly, a C string links individual characters side-by-side in memory. To let the computer know the train has ended, C attaches a special "caboose" called the Null Terminator ( \0 ). 1. Essential String Functions Handling strings manually requires complex loops. To save time, C provides a built-in library called <string.h> that contains powerful functions to manipulate text. strlen(): You use this to find the exact length of a string. The compiler counts the characters until it hits the \0 terminator. It does not count the terminator itself. strcpy(): You ...