diff --git a/uk/ac/sanger/artemis/components/alignment/BamView.java b/uk/ac/sanger/artemis/components/alignment/BamView.java
index 4802e10f4687fa948c4d4d079593d1f5c5249b79..3a37de284b06847b0ecd9c38c1cb9d302780946f 100644
--- a/uk/ac/sanger/artemis/components/alignment/BamView.java
+++ b/uk/ac/sanger/artemis/components/alignment/BamView.java
@@ -70,6 +70,9 @@ import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 import java.util.Vector;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 import javax.swing.BorderFactory;
 import javax.swing.Box;
@@ -238,6 +241,8 @@ public class BamView extends JPanel
   private JPopupMenu popup;
   private PopupMessageFrame popFrame = new PopupMessageFrame();
   private PopupMessageFrame waitingFrame = new PopupMessageFrame("waiting...");
+  private ExecutorService bamReadTaskExecutor;
+  private int MAX_COVERAGE = Integer.MAX_VALUE;
   
   public static org.apache.log4j.Logger logger4j = 
     org.apache.log4j.Logger.getLogger(BamView.class);
@@ -291,6 +296,22 @@ public class BamView extends JPanel
       }
     }
     
+    if(Options.getOptions().getIntegerProperty("bam_read_thread") != null)
+    { 
+      logger4j.debug("BAM READ THREADS="+Options.getOptions().getIntegerProperty("bam_read_thread"));
+      bamReadTaskExecutor = Executors.newFixedThreadPool(
+          Options.getOptions().getIntegerProperty("bam_read_thread"));
+    }
+    else
+      bamReadTaskExecutor = Executors.newFixedThreadPool(1);
+    
+    
+    if(Options.getOptions().getIntegerProperty("bam_max_coverage") != null)
+    { 
+      logger4j.debug("BAM MAX COVERAGE="+Options.getOptions().getIntegerProperty("bam_max_coverage"));
+      MAX_COVERAGE = Options.getOptions().getIntegerProperty("bam_max_coverage");
+    }  
+
     try
     {
       readHeaderPicard();
@@ -537,6 +558,43 @@ public class BamView extends JPanel
       seqNames.add(seq.getSequenceName());
     }
   }
+  
+  class BamReadTask implements Runnable 
+  {
+    private int start; 
+    private int end; 
+    private short bamIndex; 
+    private float pixPerBase;
+    private CountDownLatch latch;
+    BamReadTask(int start, int end, short bamIndex, float pixPerBase, CountDownLatch latch)  
+    {
+      this.start = start;
+      this.end = end;
+      this.bamIndex = bamIndex;
+      this.pixPerBase = pixPerBase;
+      this.latch = latch;
+    }
+
+    public void run() 
+    {
+      try
+      {
+        readFromBamPicard(start, end, bamIndex, pixPerBase) ;
+      }
+      catch (OutOfMemoryError ome)
+      {
+        throw ome;
+      }
+      catch(IOException me)
+      {
+        me.printStackTrace();
+      }
+      finally
+      {
+        latch.countDown();
+      }
+    }
+  }
 
   /**
    * Read a SAM or BAM file.
@@ -592,76 +650,116 @@ public class BamView extends JPanel
    * @param end
    */
   private void iterateOverBam(final SAMFileReader inputSam, 
-                              final String refName, final int start, final int end,
-                              final short bamIndex, final float pixPerBase,
-                              final String bam)
-  { 
-    final CloseableIterator<SAMRecord> it = inputSam.queryOverlapping(refName, start, end);
-    MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
+                             final String refName, final int start, final int end,
+                             final short bamIndex, final float pixPerBase,
+                             final String bam)
+  {
+    final MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
     final int checkMemAfter = 8000;
-    int cnt = 0;
     final int seqOffset = getSequenceOffset(refName);
     final int offset = seqOffset- getBaseAtStartOfView();
     final boolean isCoverageView = isCoverageView(pixPerBase);
+
+    int cnt = 0;
+
+    int nbins = 600;
+    int binSize = ((end-start)/nbins)+1;
+    if(binSize < 1)
+    {
+      binSize = 1;
+      nbins = end-start+1;
+    }
+    int max = MAX_COVERAGE*binSize;
+    if(max < 1)
+      max = Integer.MAX_VALUE;
+    final int cov[] = new int[nbins];
+    for(int i=0; i<nbins; i++)
+      cov[i] = 0;
     
-    while ( it.hasNext() )
+    final CloseableIterator<SAMRecord> it = inputSam.queryOverlapping(refName, start, end);
+    try
     {
-      try
+      while ( it.hasNext() )
       {
-        cnt++;
-        SAMRecord samRecord = it.next();
-
-        if( samRecordFlagPredicate == null ||
-           !samRecordFlagPredicate.testPredicate(samRecord))
+        try
         {
-          if(samRecordMapQPredicate == null ||
-             samRecordMapQPredicate.testPredicate(samRecord))
+          cnt++;
+          SAMRecord samRecord = it.next();
+
+          if( samRecordFlagPredicate == null ||
+             !samRecordFlagPredicate.testPredicate(samRecord))
           {
-            if(isCoverageView)
-              coverageView.addRecord(samRecord, offset, bam);
-            
-            if(isCoverage)
-              coveragePanel.addRecord(samRecord, offset, bam);
-            
-            if(isSNPplot)
-              snpPanel.addRecord(samRecord, seqOffset);
-            
-            if(!isCoverageView)
-              readsInView.add(new BamViewRecord(samRecord, bamIndex));
+            if(samRecordMapQPredicate == null ||
+               samRecordMapQPredicate.testPredicate(samRecord))
+            {
+              int abeg = samRecord.getAlignmentStart();
+              int aend = samRecord.getAlignmentEnd();
+              boolean over = false;
+              
+              for(int i=abeg; i<aend; i++)
+              {
+                
+                int bin = ((i-start)/binSize)-1;
+                if(bin < 0)
+                  bin = 0;
+                else if(bin > nbins-1)
+                  bin = nbins-1;
+                cov[bin]++;
+                if(cov[bin] > max)
+                {
+                  over = true;
+                  break;
+                }
+              }
+             
+              if(over)
+                continue;
+
+              if(isCoverageView)
+                coverageView.addRecord(samRecord, offset, bam);
+              if(isCoverage)
+                coveragePanel.addRecord(samRecord, offset, bam);
+              if(isSNPplot)
+                snpPanel.addRecord(samRecord, seqOffset);
+              if(!isCoverageView)
+                readsInView.add(new BamViewRecord(samRecord, bamIndex));
+            }
           }
-        }
         
-        if(cnt > checkMemAfter)
-        {
-          cnt = 0;
-          float heapFraction =
-            (float)((float)memory.getHeapMemoryUsage().getUsed()/
-                    (float)memory.getHeapMemoryUsage().getMax());
-          logger4j.debug("Heap memory usage (used/max): "+heapFraction);
-          
-          if(readsInView.size() > checkMemAfter*2 && !waitingFrame.isVisible())
-            waitingFrame.showWaiting("loading...", mainPanel);
-          
-          if(heapFraction > 0.90) 
+          if(cnt > checkMemAfter)
           {
-            popFrame.show(
-              "Using > 90 % of the maximum memory limit:"+
-              (memory.getHeapMemoryUsage().getMax()/1000000.f)+" Mb.\n"+
-              "Not all reads in this range have been read in. Zoom in or\n"+
-              "consider increasing the memory for this application.",
-              mainPanel,
-              15000);
-            break;
+            cnt = 0;
+            float heapFraction =
+              (float)((float)memory.getHeapMemoryUsage().getUsed()/
+                      (float)memory.getHeapMemoryUsage().getMax());
+            logger4j.debug("Heap memory usage (used/max): "+heapFraction);
+          
+            if(readsInView.size() > checkMemAfter*2 && !waitingFrame.isVisible())
+              waitingFrame.showWaiting("loading...", mainPanel);
+
+            if(heapFraction > 0.90) 
+            {
+              popFrame.show(
+                "Using > 90 % of the maximum memory limit:"+
+                (memory.getHeapMemoryUsage().getMax()/1000000.f)+" Mb.\n"+
+                "Not all reads in this range have been read in. Zoom in or\n"+
+                "consider increasing the memory for this application.",
+                mainPanel,
+                15000);
+              break;
+            }
           }
         }
-      }
-      catch(Exception e)
-      {
-        System.err.println(e.getMessage());
+        catch(Exception e)
+        {
+          System.err.println(e.getMessage());
+        }
       }
     }
-
-    it.close();
+    finally
+    {
+      it.close();
+    }
   }
 
   private int getSequenceLength()
@@ -751,7 +849,7 @@ public class BamView extends JPanel
     }
     return offsetLengths.get(refName);
   }
-  
+
   /**
    * Override
    */
@@ -807,11 +905,24 @@ public class BamView extends JPanel
           else
             readsInView.clear();
 
+          final CountDownLatch latch = new CountDownLatch(bamList.size());
+          //long ms = System.currentTimeMillis();
           for(short i=0; i<bamList.size(); i++)
           {
             if(!hideBamList.contains(i))
-              readFromBamPicard(start, end, i, pixPerBase);
+              bamReadTaskExecutor.execute(
+                  new BamReadTask(start, end, i, pixPerBase, latch));
+          }
+
+          try 
+          {
+            latch.await();
           }
+          catch (InterruptedException e) {} // TODO 
+
+          //System.out.println("===== NO. THREADS="+
+          //     ((java.util.concurrent.ThreadPoolExecutor)bamReadTaskExecutor).getPoolSize()+" TIME="+(System.currentTimeMillis()-ms));
+
           float heapFractionUsedAfter = (float) ((float) memory.getHeapMemoryUsage().getUsed() / 
                                                  (float) memory.getHeapMemoryUsage().getMax());
 
@@ -843,10 +954,6 @@ public class BamView extends JPanel
           readsInView.clear();
           return;
         }
-        catch(IOException me)
-        {
-          me.printStackTrace();
-        }
         catch(net.sf.samtools.util.RuntimeIOException re)
         {
           JOptionPane.showMessageDialog(this, re.getMessage());
@@ -1171,7 +1278,7 @@ public class BamView extends JPanel
   }
   
   /**
-   * Draw zoomed-out view.
+   * Draw inferred size view.
    * @param g2
    * @param seqLength
    * @param pixPerBase
@@ -1682,6 +1789,14 @@ public class BamView extends JPanel
     }
 
     int hgt = jspView.getVisibleRect().height-scaleHeight;
+    if(!cbCoverageStrandView.isSelected())
+    {
+      int y = getHeight()-10-( (hgt* MAX_COVERAGE)/(coverageView.max/coverageView.windowSize) );
+      g2.setColor(Color.YELLOW);
+      // draw the threshold for the coverage max read cut-off
+      g2.fillRect(0, y, getWidth(), 10);
+    }
+
     g2.translate(0, getHeight()-hgt-scaleHeight);
     coverageView.drawSelectionRange(g2, pixPerBase, start, end, getHeight(), Color.PINK);
     coverageView.draw(g2, getWidth(), hgt);
@@ -2624,6 +2739,28 @@ public class BamView extends JPanel
       } 
     });
     
+    JMenuItem maxReadCoverage = new JMenuItem("Read Coverage Threshold ...");
+    menu.add(maxReadCoverage);
+    maxReadCoverage.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        final TextFieldInt maxRead = new TextFieldInt();
+        maxRead.setValue(MAX_COVERAGE);
+        int status = JOptionPane.showConfirmDialog(null, maxRead, 
+            "Read Coverage Threshold", JOptionPane.OK_CANCEL_OPTION);
+        if(status == JOptionPane.OK_OPTION &&
+           maxRead.getValue() != MAX_COVERAGE)
+        {
+          MAX_COVERAGE = maxRead.getValue();
+          if(MAX_COVERAGE < 1)
+            MAX_COVERAGE = Integer.MAX_VALUE;
+          laststart = -1;
+          repaint();
+        }
+      } 
+    });
+    
     JMenuItem readList = new JMenuItem("List Reads ...");
     menu.add(readList);
     readList.addActionListener(new ActionListener()