5/18/2007

When to join threads

Let's say I need to spawn multiple threads to do the work, and continue to the next step only after all of them complete. I will need to tell the main thread to wait. The key point is to use Thread.join() method. For example,

package foo;
import java.util.Vector;
public class ThreadTest {
private Vector<String> threadNames = new Vector<String>();
public static void main(String[] args) {
ThreadTest test = new ThreadTest();
test.threadTest(Integer.parseInt(args[0]));
System.out.println(test.threadNames);
}
private void threadTest(int numOfThreads) {
Thread[] threads = new Thread[numOfThreads];
for (int i = 0; i < threads.length; i++) {
threads[i] = new foo.ThreadTest.MyThread();
threads[i].start();
}
for (int i = 0; i < threads.length; i++) {
try {
threads[i].join();
} catch (InterruptedException ignore) {}
}
}
class MyThread extends Thread {
public void run() {
for (int i = 0; i < 1000000; i++) {
i = i + 0;
}
threadNames.add(getName());
}
}
}
The output when running this program with 10 threads:
[Thread-1, Thread-3, Thread-0, Thread-5, Thread-7, Thread-6, Thread-9, Thread-2, Thread-8, Thread-4]
The order in which the threads are executed is random, which is expected.

Also note that we use two for-loops, the first to create and start each thread, and the second loop to join each thread. If each thread is joined right after start, the effect is these threads are executed sequentially, without the desired concurrency. For example, the following code snippet results in serial execution:
// The following is NOT concurrent:
//
private void threadTest(int numOfThreads) {
Thread[] threads = new Thread[numOfThreads];
for (int i = 0; i < threads.length; i++) {
threads[i] = new foo.ThreadTest.MyThread();
threads[i].start();
try {
threads[i].join();
} catch (InterruptedException ignore) {
}
}
}
Output:

[Thread-0, Thread-1, Thread-2, Thread-3, Thread-4, Thread-5, Thread-6, Thread-7, Thread-8, Thread-9]
If we don't use any join at all, threadNames, when printed, may be empty, or partially filled, since the main thread will just move on when it gets the chance. The main thread will still wait, at the very last step, for all threads to complete, before exiting the JVM. The output for running 10 threads may be:
[Thread-0, Thread-1, Thread-2, Thread-3]
The following is a general-purpose code skeleton for running concurrency test using anonymous Runnable inner-class:

Thread[] threads = new Thread[numOfThreads];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
public void run() {
System.out.println("xxx");
}
});
threads[i].start();
}
for (int i = 0; i < threads.length; i++) {
try {
threads[i].join();
} catch (InterruptedException e) {
}
}
Another version using java.util.concurrent.CountDownLatch: When to join threads with CountDownLatch

Tags: ,

5/03/2007

My glassfish password file


AS_ADMIN_MASTERPASSWORD=changeit
AS_ADMIN_PASSWORD=adminadmin
AS_ADMIN_USERPASSWORD=xxx
password.txt contains the above password values. Glassfish application server doesn't allow you to specify password as command line arguments (or at least it gives warning). Instead, it uses the --passwordfile argument to get passwords from a plain text file, which can only be accessed by the owner.

Nobody can memorize these keys, and several times I forgot where I saved this file. So keep a copy here for future copy-paste.

If the keys in the password file are not what glassfish expected, it gives this warning:
Options specified in passwordfile are either invalid or deprecated. Passwordfile can only be used to specify values for password options. Use of passwordfile to specify values for other options is deprecated. Passwordfile should contain the following format AS_ADMIN_=.