diff --git a/src/interfaces/jdbc/example/ImageViewer.java b/src/interfaces/jdbc/example/ImageViewer.java
index 9e93d83c7c3a4356195f0907d2d043bb9aa5836a..8f6f4c5e68f4f522b0a0ea412f05dc389e2ee523 100644
--- a/src/interfaces/jdbc/example/ImageViewer.java
+++ b/src/interfaces/jdbc/example/ImageViewer.java
@@ -26,6 +26,9 @@ import postgresql.largeobject.*;
  * It's only if you use the non jdbc facilities, do you have to take this into
  * account.
  *
+ * Note: For PostgreSQL 6.4, the driver is now Thread safe, so this example
+ * application has been updated to use multiple threads, especially in the
+ * image storing and retrieving methods.
  */
 
 public class ImageViewer implements ItemListener
@@ -42,8 +45,15 @@ public class ImageViewer implements ItemListener
   // This is a simple component to display our image
   public class imageCanvas extends Canvas
   {
+    // holds the image
     private Image image;
     
+    // holds the background buffer
+    private Image bkg;
+    
+    // the size of the buffer
+    private Dimension size;
+    
     public imageCanvas()
     {
       image=null;
@@ -71,14 +81,35 @@ public class ImageViewer implements ItemListener
       paint(g);
     }
     
-    public void paint(Graphics g)
+    /**
+     * Paints the image, using double buffering to prevent screen flicker
+     */
+    public void paint(Graphics gr)
     {
+      Dimension s = getSize();
+      
+      if(size==null || bkg==null || !s.equals(size)) {
+	size = s;
+	bkg = createImage(size.width,size.height);
+      }
+      
+      // now set the background
+      Graphics g = bkg.getGraphics();
       g.setColor(Color.gray);
-      g.fillRect(0,0,getSize().width,getSize().height);
+      g.fillRect(0,0,s.width,s.height);
       
+      // now paint the image over the background
       if(image!=null)
 	g.drawImage(image,0,0,this);
+      
+      // dispose the graphics instance
+      g.dispose();
+      
+      // paint the image onto the component
+      gr.drawImage(bkg,0,0,this);
+      
     }
+    
   }
   
   public ImageViewer(Frame f,String url,String user,String password) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
@@ -197,9 +228,8 @@ public class ImageViewer implements ItemListener
   }
   
   /**
-   * This imports an image into the database.
-   *
-   * This is the most efficient method, using the large object extension.
+   * This imports an image into the database, using a Thread to do this in the
+   * background.
    */
   public void importImage()
   {
@@ -209,51 +239,92 @@ public class ImageViewer implements ItemListener
     String dir = d.getDirectory();
     d.dispose();
     
-    // Now the real import stuff
-    if(name!=null && dir!=null) {
-      try {
-	System.out.println("Importing file");
-	// A temporary buffer - this can be as large as you like
-	byte buf[] = new byte[2048];
-	
-	// Open the file
-	System.out.println("Opening file "+dir+"/"+name);
-	FileInputStream fis = new FileInputStream(new File(dir,name));
-	
-	// Gain access to large objects
-	System.out.println("Gaining LOAPI");
-	
-	// Now create the large object
-	System.out.println("creating blob");
-	int oid = lom.create();
-	
-	System.out.println("Opening "+oid);
-	LargeObject blob = lom.open(oid);
+    // now start the true importer
+    Thread t = new importer(db,name,dir);
+    //t.setPriority(Thread.MAX_PRIORITY);
+    t.start();
+  }
+  
+  /**
+   * This is an example of using a thread to import a file into a Large Object.
+   * It uses the Large Object extension, to write blocks of the file to the
+   * database.
+   */
+  class importer extends Thread
+  {
+    String name,dir;
+    Connection db;
+    
+    public importer(Connection db,String name,String dir) {
+      this.db = db;
+      this.name = name;
+      this.dir = dir;
+    }
+    
+    public void run() {
+      
+      // Now the real import stuff
+      if(name!=null && dir!=null) {
+	Statement stat = null;
 	
-	// Now copy the file into the object.
-	//
-	// Note: we dont use write(buf), as the last block is rarely the same
-	// size as our buffer, so we have to use the amount read.
-	System.out.println("Importing file");
-	int s,t=0;
-	while((s=fis.read(buf,0,buf.length))>0) {
-	  System.out.println("Block s="+s+" t="+t);t+=s;
-	  blob.write(buf,0,s);
+	try {
+	  // fetch the large object manager
+	  LargeObjectManager lom = ((postgresql.Connection)db).getLargeObjectAPI();
+	  
+	  System.out.println("Importing file");
+	  // A temporary buffer - this can be as large as you like
+	  byte buf[] = new byte[2048];
+	  
+	  // Open the file
+	  System.out.println("Opening file "+dir+"/"+name);
+	  FileInputStream fis = new FileInputStream(new File(dir,name));
+	  
+	  // Gain access to large objects
+	  System.out.println("Gaining LOAPI");
+	  
+	  // Now create the large object
+	  System.out.println("creating blob");
+	  int oid = lom.create();
+	  
+	  System.out.println("Opening "+oid);
+	  LargeObject blob = lom.open(oid);
+	  
+	  // Now copy the file into the object.
+	  //
+	  // Note: we dont use write(buf), as the last block is rarely the same
+	  // size as our buffer, so we have to use the amount read.
+	  System.out.println("Importing file");
+	  int s,t=0;
+	  while((s=fis.read(buf,0,buf.length))>0) {
+	    System.out.println("Block s="+s+" t="+t);t+=s;
+	    blob.write(buf,0,s);
+	  }
+	  
+	  // Close the object
+	  System.out.println("Closing blob");
+	  blob.close();
+	  
+	  // Now store the entry into the table
+	  
+	  // As we are a different thread to the other window, we must use
+	  // our own thread
+	  stat = db.createStatement();
+	  stat.executeUpdate("insert into images values ('"+name+"',"+oid+")");
+	  
+	  // Finally refresh the names list, and display the current image
+	  ImageViewer.this.refreshList();
+	  ImageViewer.this.displayImage(name);
+	} catch(Exception ex) {
+	  label.setText(ex.toString());
+	} finally {
+	  // ensure the statement is closed after us
+	  try {
+	    if(stat != null)
+	      stat.close();
+	  } catch(SQLException se) {
+	    System.err.println("closing of Statement failed");
+	  }
 	}
-	
-	// Close the object
-	System.out.println("Closing blob");
-	blob.close();
-	
-	// Now store the entry into the table
-	stat.executeUpdate("insert into images values ('"+name+"',"+oid+")");
-	stat.close();
-	
-	// Finally refresh the names list, and display the current image
-	refreshList();
-	displayImage(name);
-      } catch(Exception ex) {
-	label.setText(ex.toString());
       }
     }
   }
@@ -364,7 +435,7 @@ public class ImageViewer implements ItemListener
     }
     
     try {
-      Frame frame = new Frame("PostgreSQL ImageViewer v6.3 rev 1");
+      Frame frame = new Frame("PostgreSQL ImageViewer v6.4 rev 1");
       frame.setLayout(new BorderLayout());
       ImageViewer viewer = new ImageViewer(frame,args[0],args[1],args[2]);
       frame.pack();