DEV Community

wennan xu
wennan xu

Posted on • Edited on

Thread safe strategy in Java or .net

Stateless design

Just like in Java, designing classes without shared mutable state is the safest approach.

public class MyProcessor
{
    public string Process(string input)
    {
        return input.ToUpper(); // No shared state
    }
}

Enter fullscreen mode Exit fullscreen mode

ThreadLocal

ThreadLocal is a .NET class that allows you to store data that is local to a specific thread. Each thread accessing a ThreadLocal instance gets its own independent copy of the data.

private static ThreadLocal<Random> random = new ThreadLocal<Random>(() => new Random());

public int GetRandomNumber()
{
    return random.Value.Next();
}

Enter fullscreen mode Exit fullscreen mode

Synchronized blocks

Use lock (or Monitor) to protect shared resources.

private readonly object _lock = new object();
private List<string> _sharedList = new List<string>();

public void AddItems(List<string> items)
{
    lock (_lock)
    {
        _sharedList.AddRange(items);
    }
}

Enter fullscreen mode Exit fullscreen mode

ReentrantLock — More powerful, flexible locking with timeout

ReentrantLock lock = new ReentrantLock();

try {

    acquired = lock.tryLock(500, TimeUnit.MILLISECONDS);
    if (acquired) {
        System.out.println("Lock acquired, doing work...");
        // critical section
        Thread.sleep(1000); // simulate work
    } else {
        System.out.println("Could not acquire lock within timeout.");
    }
} finally {
    lock.unlock();
}

Enter fullscreen mode Exit fullscreen mode

ReentrantReadWriteLock — More powerful and more flexible, providing two locks - readLock and writelock with timeout, Effect: Multiple threads can read concurrently. Only one thread can write, and it blocks all readers.

Concurrency: Much better for read-heavy workloads.


private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();

public String read(String key) {
    readLock.lock();
    try {
        return sharedMap.get(key);
    } finally {
        readLock.unlock();
    }
}

public void write(String key, String value) {
    writeLock.lock();
    try {
        sharedMap.put(key, value);
    } finally {
        writeLock.unlock();
    }
}
Enter fullscreen mode Exit fullscreen mode

Thread-safe collections

Thread-safe collections are designed to handle concurrent access without requiring manual locking.
Common Thread-Safe Collections in .NET

Collection               Use Case
ConcurrentDictionary    Key-value store with safe concurrent access
ConcurrentQueue         FIFO queue for producer-consumer scenarios
ConcurrentStack         LIFO stack for concurrent access
ConcurrentBag           Unordered collection for fast insert/retrieve
BlockingCollection  Thread-safe wrapper for producer-consumer with blocking and bounding
Enter fullscreen mode Exit fullscreen mode

Partitioning

Similar to Spring Batch partitioning, you can divide work into chunks and assign each to a separate thread or task.

Parallel.ForEach(partitions, partition =>
{
    ProcessPartition(partition);
});

Enter fullscreen mode Exit fullscreen mode

Immutable data

Immutable types are inherently thread-safe. You can use records or readonly structs in C#.

public record Person(string Name, int Age);
Enter fullscreen mode Exit fullscreen mode

Top comments (0)