I am trying to solve the N Queen problem using multiple threads. However, the single threaded version of it runs either faster or roughly the same as the multithreaded one.
In essence, I use a queue which all the threads share. They pop states from the queue and expand them and add then them to the queue. I have tried playing around with the number of threads but to no avail, the more threads I add after around 8 the performance degenerates. The algorithm is correct in that the output is the same in both versions.
Any ideas?
Here's the code:
public class Queens { //Thread static class Runner implements Runnable { private BlockingQueue<Configuration> queue; private final AtomicInteger total; public Runner(BlockingQueue<Configuration> q, AtomicInteger total) { this.queue = q; this.total = total; } public void run() { while(!queue.isEmpty()) { Configuration currentConfiguration = null; try { currentConfiguration = queue.take(); } catch(InterruptedException e) { } if(currentConfiguration.done()) { //currentConfiguration.printConfiguration(); total.incrementAndGet(); System.out.println("Solution"); continue; } for(int i = 0; i < currentConfiguration.getSize(); i++) { if(safe(currentConfiguration, i, currentConfiguration.getColumn())) { Configuration childConfig = new Configuration(currentConfiguration.getColumn() + 1, currentConfiguration.getBoard()); childConfig.place(i, currentConfiguration.getColumn()); queue.add(childConfig); } } } } //Returns true if we can place a queen on that row and column. private boolean safe(Configuration current, int row, int col) { for (int i = 0; i < col; i++) if (current.getBoard()[row][i] == 1) return false; for (int i = row, j = col; i >= 0 && j >= 0; i--, j--) if (current.getBoard()[i][j] == 1) return false; for (int i = row, j = col; j >= 0 && i < current.getSize(); i++, j--) if (current.getBoard()[i][j] == 1) return false; return true; } } //Board configuration class. static class Configuration { private int column; private int[][] board; private int size; public Configuration(int column, int[][] b) { this.column = column; this.board = new int[b.length][b.length]; this.size = b.length; for(int i = 0; i < size; i++) { for(int j = 0; j < size; j++) { board[i][j] = b[i][j]; } } } public int getSize() { return size; } public int getColumn() { return column; } public int[][] getBoard() { return board; } public boolean done() { if(column == size) return true; return false; } public void place(int row, int column) { board[row][column] = 1; } //Method prints the current configuration. public synchronized void printConfiguration() { synchronized(Configuration.class) { System.out.println(Thread.currentThread().getName()); for(int i = 0; i < size; i++) { for(int j = 0; j < size; j++) { System.out.print(board[i][j] + " "); } System.out.println(); } } } } public static void main(String[] args) throws InterruptedException { Configuration x = new Configuration(0, new int[13][13]); int threads = 10; AtomicInteger totalSolutions = new AtomicInteger(0); List<Thread> mythreads = new ArrayList<Thread>(); BlockingQueue<Configuration> q = new LinkedBlockingDeque<>(); //Initially the board is empty q.put(x); long startTime = System.currentTimeMillis(); //Run 10 threads for(int i = 0; i < threads; i++) { Thread newthread = new Thread(new Runner(q, totalSolutions)); newthread.start(); mythreads.add(newthread); } for(Thread t : mythreads) { try { t.join(); } catch(Exception e) {}; } System.out.println(totalSolutions.get()); long endTime = System.currentTimeMillis(); System.out.println("Time: " + (endTime - startTime)); } }