Tuesday, August 31, 2010

Getting to Know Threads

Threads have six possible states:
new, runnable, blocked, waiting, timed waiting, terminated

A thread terminates when its run() method returns.

interrupt() can interrupt a thread (or, it may cause a SecurityException to be thrown). If the thread is in a non-blocked status, it can call Thread.getCurrentThread().isInterrupted() to check if interrupt has been called. If the thread is in a blocked status such as sleep, another thread's call to interrupt() will cause an InterruptedException which will cause the thread to exit sleep or wait.

The functionality of the synchronized keyword has been extended with java.util.concurrent.locks.Lock.

Below is code which shows two means of creating threads. The code performs the simplest use case for threads, no shared state.
public class Main extends Thread {
    
    public Main(String name) {
        super(name);
    }
    
    public static void main(String[] args) throws Exception {
        Main m = new Main("1st");
        m.start(); 
        
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int x = 0; x < 5; x++) { 
                    System.out.println("Runnable:  name=" + Thread.currentThread().getName() + ": x=" + x);
                    try { 
                        sleep(10);
                    } catch(InterruptedException e) {
                        System.out.println("Runnable interrupted");
                    }
                }
            }
        }, "2nd").start();
    }
    
    @Override
    public void run() {
        for (int x = 0; x < 5; x++) { 
            System.out.println("Thread:    name=" + Thread.currentThread().getName() + ": x=" + x);
            try { 
                sleep(10);
            } catch(InterruptedException e) {
                System.out.println("Thread interrupted");
            }
        }
    } 
}
<project name="java_concurrency" default="run" basedir=".">
    <property name="src.dir"           location="src/main/java"/> 
    <property name="test.src.dir"      location="src/test/java"/>
    <property name="build.dir"         location="build"/>
    <property name="classes.dir"       location="build/classes"/>
    <property name="tests.dir"         location="build/tests"/>
    <property name="junit.jar"         location="lib/junit/junit-4.8.2.jar"/>
    <path id="compile.classpath">
        <pathelement location="${classes.dir}"/>
    </path>

    <path id="test.classpath">
        <pathelement location="${classes.dir}"/>
        <pathelement location="${junit.jar}"/>
        <pathelement location="${tests.dir}"/>
    </path>
    
    <path id="run.classpath">
        <pathelement location="${classes.dir}"/>
    </path>

    <target name="clean">
        <delete dir="${build.dir}"/>
    </target>

    <target name="init" depends="clean">
        <mkdir dir="${classes.dir}"/>
        <mkdir dir="${tests.dir}"/>
    </target>

    <target name="compile" depends="init">
        <javac srcdir="${src.dir}" 
            destdir="${classes.dir}" 
            classpathref="compile.classpath"/>
        <javac srcdir="${test.src.dir}" 
            destdir="${tests.dir}" 
            classpathref="test.classpath"/>
    </target>
  
    <target name="test" depends="compile">
        <junit fork="yes" printsummary="yes">
            <classpath refid="test.classpath"/>
            <formatter type="plain" usefile="false"/>
            <test name="MainTest"/>
        </junit>
    </target>
    
    <target name="run" depends="compile">
        <java fork="true" dir="${classes.dir}" classname="Main" classpathref="run.classpath"/>
    </target> 
</project>
[greg:java_concurrency] ant
. . . 
run:
     [java] Runnable:  name=2nd: x=0
     [java] Thread:    name=1st: x=0
     [java] Runnable:  name=2nd: x=1
     [java] Thread:    name=1st: x=1
     [java] Runnable:  name=2nd: x=2
     [java] Thread:    name=1st: x=2
     [java] Runnable:  name=2nd: x=3
     [java] Thread:    name=1st: x=3
     [java] Runnable:  name=2nd: x=4
     [java] Thread:    name=1st: x=4
[greg:java_concurrency]