Archive

Archive for February, 2013

Series About Java Concurrency – Pt. 6

February 15, 2013 Leave a comment

This is the solution to my previous post, so make sure that you read it before you continue. For your convenience, here is the program we are going to discuss once again:

public class ThreadNoMore extends Thread
{
    private static final int N_THREADS = 16;
    private static final AtomicInteger threadsStarted = new AtomicInteger();
    
    private final long ctorThreadId = Thread.currentThread().getId();
    
    @Override
    public synchronized void start()
    {
        if(ctorThreadId != Thread.currentThread().getId())
            threadsStarted.incrementAndGet();
    }
    
    public static void main(String[] args) throws InterruptedException
    {
        Thread[] threads = new Thread[N_THREADS];
        for(int i = 0; i != N_THREADS; ++i)
            threads[i] = new ThreadNoMore();
        
        for(Thread th : threads)
            th.start();
        
        for(Thread th : threads)
            th.join();
        
        System.out.println("threadsStarted: " + threadsStarted);
    }
}

As already pointed out by Ortwin Glück, the program always prints

threadsStarted: 0

because ThreadNoMore.start() is always executed in thread that invoked it. And if you think that over twice, this should not surprise you at all, as methods are always executed in the thread that invoked them. This even applies to Thread.run(), which is the method we should have overridden instead, but unlike Thread.start(), Thread.run() is normally invoked by the Java Virtual Machine, as the Javadocs for Thread.start() tell us:

Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.

So apart from not doing what we might have intended, carelessly overriding Thread.start(), that is without calling super.start(), so that the JVM can do its magic, leaves us with a crippled class, that no longer has anything to do with a thread at all. Considering these facts, it should not take you by surprise that

public class Thrap extends Thread
{
    private static final int N_THREADS = 42;
    
    private static final AtomicInteger 
        started = new AtomicInteger(),
        ran = new AtomicInteger();
    
    @Override
    public synchronized void start()
    {
        started.incrementAndGet();
    }
    
    @Override
    public void run()
    {
        ran.incrementAndGet();
    }
    
    public static void main(String[] args) throws InterruptedException
    {
        Thread[] threads = new Thread[N_THREADS];
        for(int i = 0; i != N_THREADS; ++i)
            threads[i] = new Thrap();
        
        for(Thread thread : threads)
            thread.start();
        
        for(Thread thread : threads)
            thread.join();
        
        System.out.println("started: " + started);
        System.out.println("ran: " + ran);
    }
}

results in

started: 42
ran: 0

being written to your terminal. As you can see clearly, Thrap.run() is not executed at all, neither from a newly created, nor from the main thread. The fix the code above, you have to call super.start() in Thrap.start() like so:

    @Override
    public synchronized void start()
    {
        super.start();
        startedThreads.incrementAndGet();
    }

After this modification you get

started: 42
ran: 42

as expected.

So what can we learn from all of this? At first, there are two things to remember about the Java threads API:

Equally important are the consequences for API design: Interfaces should be easy to use correctly and hard to use incorrectly. Unfortunately the Thread class violates this principle, as it is quite easy to misuse as we have just seen. More generally, requiring clients to call the super version of a method they are overriding is considered to be an anti pattern for this very reason.

Advertisements
Categories: Programming Tags: , ,

Series About Java Concurrency – Pt. 5

February 13, 2013 1 comment

After quite some time, here is a concurrency related puzzle once again: Take a look at the following program and try to predict its output:

package com.wordpress.mlangc.concurrent;

import java.util.concurrent.atomic.AtomicInteger;

public class ThreadNoMore extends Thread
{
    private static final int N_THREADS = 16;
    private static final AtomicInteger threadsStarted = new AtomicInteger();
    
    private final long ctorThreadId = Thread.currentThread().getId();
    
    @Override
    public synchronized void start()
    {
        if(ctorThreadId != Thread.currentThread().getId())
            threadsStarted.incrementAndGet();
    }
    
    public static void main(String[] args) throws InterruptedException
    {
        Thread[] threads = new Thread[N_THREADS];
        for(int i = 0; i != N_THREADS; ++i)
            threads[i] = new ThreadNoMore();
        
        for(Thread th : threads)
            th.start();
        
        for(Thread th : threads)
            th.join();
        
        System.out.println("threadsStarted: " + threadsStarted);
    }
}

The solution, together with a detailed explanation will be available soon.

Categories: Programming Tags: , ,