You have two problems. One is that threads take a while to start, so you're giving "Low" a pretty good head start by firing them off serially. The other is that thread priority decides who gets to run when there's an argument for processor time. With two threads and 8 effective processor cores, priority isn't going to matter a whole lot! Here is a fixed example that uses a latch to start all threads as "simultaneously" and uses enough threads that they actually fight over resources and you can see the effect of priority settings. It gives pretty consistent results.
static class Clicker implements Runnable{
BigInteger click = BigInteger.ZERO;
Thread t;
Clicker(int p){
t=new Thread(this);
t.setPriority(p);
}
public void run(){
try {
latch.await();
} catch(InterruptedException ie) {}
while(running)
click = click.add(BigInteger.ONE);
}
public void start(){
t.start();
}
}
public static volatile boolean running = true;
public static final CountDownLatch latch = new CountDownLatch(1);
public static void main(String args[]){
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
List<Clicker> listLow = new ArrayList<Clicker>();
List<Clicker> listHigh = new ArrayList<Clicker>();
for (int i = 0; i < 16; i++) {
listHigh.add(new Clicker(Thread.NORM_PRIORITY+4));
}
for (int i = 0; i < 16; i++) {
listLow.add(new Clicker(Thread.NORM_PRIORITY-4));
}
for (Clicker clicker: listLow) {
clicker.start();
}
for (Clicker clicker: listHigh) {
clicker.start();
}
latch.countDown();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
running = false;
BigInteger lowTotal = BigInteger.ZERO;
BigInteger highTotal = BigInteger.ZERO;
try {
for (Clicker clicker: listLow) {
clicker.t.join();
lowTotal = lowTotal.add(clicker.click);
}
for (Clicker clicker: listHigh) {
clicker.t.join();
highTotal = highTotal.add(clicker.click);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("LO: "+lowTotal);
System.out.println("HI: "+highTotal);
}