/////////////////////////////////////////////////////////////////
// StackTrace.java
import java.io.*;
/**
* Demonstrates how to get a stack trace as a String
* @author Jonathan Locke
*/
public class StackTrace
{
/**
* Returns a stack trace for the calling thread
* @return Stack trace of calling thread as a String.
*/
public static String getStackTrace()
{
CharArrayWriter c = new CharArrayWriter();
new Exception("Test").printStackTrace(new PrintWriter(c));
return c.toString();
}
/**
* Main application entrypoint.
* @param arg Command line arguments
*/
static public void main(String[] arg)
{
System.out.println(getStackTrace());
}
}
Figure 2 Traversing a Directory Tree
Walk.java
/////////////////////////////////////////////////////////////////
//
// Walk.java
//
import java.io.*;
/**
* Walks a directory tree making callbacks to a WalkObserver
* @author Jonathan Locke
*/
public class Walk
{
/**
* Walks a directory tree, calling the WalkObserver at each file.
* @param rootDirectory Root of directory tree to walk
* @param o The directory WalkObserver object for callbacks
* @param indentLevel The current level of recursion
*/
static void walk(File rootDirectory, WalkObserver o, int indentLevel)
{
// Get list of files in directory
String[] file = rootDirectory.list();
// Traverse files
for (int i = 0; i < file.length; i++)
{
// Call observer callback with file
File f = new File(rootDirectory, file[i]);
o.at(f, indentLevel);
// If the file is a directory, recurse into it
if (f.isDirectory())
{
walk(f, o, indentLevel + 1);
}
}
}
}
WalkObserver.java
/////////////////////////////////////////////////////////////////
//
// WalkObserver.java
//
import java.io.*;
/**
* Interface for objects that want to observe directory traversals.
* @author Jonathan Locke
*/
public interface WalkObserver
{
/**
* The WalkObserver entrypoint. Shows each file in a tree traversal.
* @param f File encountered
* @param indentLevel Level of recursion
*/
public void at(File f, int indentLevel);
}
Figure 3 FinalizeMe.java
/////////////////////////////////////////////////////////////////
//
// FinalizeMe.java
//
/**
* A test program to demonstrate finalization
* @author Jonathan Locke
*/
public class FinalizeMe
{
/**
* Called after object becomes unreachable, but before
* garbage collection of the object
*/
protected void finalize() throws Throwable
{
super.finalize();
System.out.println("In finalizer!");
}
/**
* Main application entrypoint.
* @param arg Command line arguments
*/
static public void main(String[] arg)
{
// Create a FinalizeMe object
FinalizeMe f = new FinalizeMe();
// Force a garbage collection
System.out.println("First gc");
System.gc();
System.runFinalization();
// Get rid of last reference to object
f = null;
// Force a garbage collection
System.out.println("Second gc");
System.gc();
System.runFinalization();
System.out.println("Done.");
}
}
Figure 4 Deadlock.java
/////////////////////////////////////////////////////////////////
//
// Deadlock.java
//
/**
A demonstration of deadlocking in Java.
* @author Jonathan Locke
*/
public class Deadlock implements Runnable
{
Object ready = new Object(); // Main referee thread waits on this object
// for both threads to get ready
Object go = new Object(); // The wantsSalt and wantsPepper threads wait
// on this until the referee says "go!"
Object salt = new Object(); // The salt object
Object pepper = new Object(); // The pepper object
/**
* The wantsSalt thread's agenda
*/
void wantsSalt()
{
synchronized (pepper)
{
System.out.println("wantsSalt: I've got the pepper and I'm ready to go.");
synchronized(ready)
{
ready.notifyAll();
}
try
{
synchronized(go)
{
go.wait();
}
}
catch (InterruptedException e)
{
}
System.out.println("wantsSalt: If you first give the salt, then I'll
give you the pepper.");
System.out.println("wantsSalt: Waiting for the salt.");
synchronized (salt)
{
Object o = salt;
System.out.println("wantsSalt: Thanks, I've got exclusive access to
the salt now.");
}
}
System.out.println("wantsSalt: You can now have the pepper.");
}
/**
* The wantsPepper thread's agenda
*/
void wantsPepper()
{
synchronized (salt)
{
System.out.println("wantsPepper: I've got the salt and I'm ready to go.");
synchronized(ready)
{
ready.notifyAll();
}
try
{
synchronized(go)
{
go.wait();
}
}
catch (InterruptedException e)
{
}
System.out.println("wantsPepper: If you first give me the pepper, then
I'll give you the salt.");
System.out.println("wantsPepper: Waiting for the pepper.");
synchronized (pepper)
{
Object o = pepper;
System.out.println("wantsPepper: Thanks, I've got exclusive access
to the pepper now.");
}
System.out.println("");
}
System.out.println("wantsPepper: You can now have the salt.");
}
/**
* Entrypoint for threads.
*/
public void run()
{
if (Thread.currentThread().getName().equals("wantsSalt"))
{
wantsSalt();
}
else
{
wantsPepper();
}
}
/**
* Constructor
*/
public Deadlock()
{
synchronized(ready)
{
new Thread(this, "wantsSalt").start();
new Thread(this, "wantsPepper").start();
try
{
System.out.println("referee: Waiting for first thread");
ready.wait();
System.out.println("referee: Waiting for second thread");
ready.wait();
}
catch (InterruptedException e)
{
}
}
synchronized(go)
{
System.out.println("referee: Now you may begin!!");
go.notifyAll();
}
}
/**
* Main application entrypoint.
* @param arg Command line arguments
*/
static public void main(String[] arg)
{
new Deadlock();
}
}