Java 中使用 lambda 和 Callable 的数独多线程
Sudoku Multithreading with lambda and Callable in Java
我制作了一个程序来检查完成的 9x9 数独矩阵是否正确。我想创建同时检查行、列和区域的线程,以查看数字 1-9 是否出现在其中。我不熟悉使用 Callable 和 lambda。到目前为止,这是我的代码:
public class Sudoku {
public boolean testBoard(int[][] board) throws InterruptedException, ExecutionException {
List<Callable<Boolean>> tests = new ArrayList<>();
tests.add(() -> testCols(board));
tests.add(() -> testRegions(board));
tests.add(() -> testRows(board));
tests.add(() -> testSize(board));
/*Maybe store this threadPool in a field so you dont create it everytime*/
ExecutorService threadPool = Executors.newCachedThreadPool();
List<Future<Boolean>> results = threadPool.invokeAll(tests);
for (Future<Boolean> future : results) {
if (!Boolean.TRUE.equals(future.get())) {
return false;
}
}
return true;
}
// check that the board is 9 x 9
boolean testSize(int[][] board) {
if (board.length != 9) {
return false;
}
for (int i = 0; i < board.length; i++) {
if (board[i].length != 9) {
return false;
} else;
}
return true;
}
// check that the digits 1-9 each appear exactly once in the given array
boolean checkDigits(int[] array) {
if (array.length != 9) {
return false;
}
int[] counts = new int[10];
for (int i = 0; i
< array.length; i++) {
// invalid number
if (array[i] < 1 || array[i] > 9) {
return false;
}
// we have already seen this number
if (counts[array[i]] > 0) {
return false;
}
counts[array[i]]++;
}
return true;
}
// return true if all rows are correct
boolean testRows(int[][] board) {
for (int i = 0; i < board.length; i++) {
if (!checkDigits(board[i])) {
return false;
}
}
return true;
}
// return true if all columns are correct
boolean testCols(int[][] board) {
int[] tmp = new int[board.length];
for (int col = 0; col < board.length; col++) {
// fill a temp array with every element of the column
for (int row = 0; row < board.length; row++) {
tmp[row]
= board[row][col];
}
// check to make sure it has all the right digits
if (!checkDigits(tmp)) {
return false;
}
}
return true;
}
// return true if every region is correct
boolean testRegions(int[][] board) {
//loop through each region, passing the indices of the upper-left corner to the next method
//note that we increment row and column counters by 3 here
for (int row = 0; row < board.length; row += 3) {
for (int col = 0; col
< board.length; col += 3) {
if (!testRegion(board, row, col)) {
return false;
}
}
}
return true;
}
// test a specific region, given the upper left corner
boolean testRegion(int[][] board, int startRow, int startCol) {
int[] tmp = new int[board.length];
// fill a temporary array with every element of the region
int index = 0;
for (int row = startRow; row < startRow + 3; row++) {
for (int col = startCol; col < startCol + 3; col++) {
tmp[index]
= board[row][col];
index++;
}
}
// check if we have all of the right digits in the region
return checkDigits(tmp);
}
}
public class TestPuzzle {
public static void testpuzzle() throws FileNotFoundException, InterruptedException, ExecutionException{
Sudoku sudoku = new Sudoku();
String fileName = "SudokuRight.txt";//This is for the print statment
Scanner inputStream = null;
String[] line;
System.out.println("The file " + fileName + " contains the following sudoku puzzle:\n");
inputStream = new Scanner(new File("C:\Users\username\Documents\NetBeansProjects\Sudoku\SudokuRight.txt"));
int[][] puzzle = new int[9][9];
int row = 0;
while (inputStream.hasNextLine()) {
line = inputStream.nextLine().split(",");
for (int i = 0; i < 9; i++) {
puzzle[row][i] = Integer.parseInt(line[i]);
}
row++;
}
for (int i = 0; i < 9; i++) {
System.out.println(Arrays.toString(puzzle[i]));
}
boolean result = sudoku.testBoard(puzzle);
System.out.println("Result: " + result);
if (result == true) {
System.out.println("This sudoku solution IS valid!");
} else if (result == false) {
System.out.println("This sudoku solution IS NOT valid!");
}
}
}
public class Main {
//This is the main method to check the validity of sudoku puzzles
public static void main(String[] args) throws FileNotFoundException, InterruptedException, ExecutionException {
TestPuzzle.testpuzzle();
}
}
有人试图教我如何使用 callable 和 lambda,但我仍然有点困惑。我的代码现在 运行 正确,但是,在 NetBeans 中打印出结果后,它会继续 运行 直到我手动终止它。我不确定为什么?我以为我的代码中必须有这样的语句块:
Callable<Boolean> callable = () -> Boolean.valueOf(testCols(board));
Callable<Boolean> callable = () -> Boolean.valueOf(testRows(board));
Callable<Boolean> callable = () -> Boolean.valueOf(testRegions(board));
Callable<Boolean> callable = () -> Boolean.valueOf(testSize(board));
但是我不确定将这些行放在哪里?我不能将它们放入构造函数中,因为 "board" 尚未初始化。我确定这是一个简单的修复,因为我是新手,所以我被卡住了。有什么帮助吗?
根据我的评论,我认为您的问题是您在向执行程序服务添加所有 Callable 并调用它们之后没有调用 shutdown()
。我建议你这样做:
ExecutorService threadPool = Executors.newCachedThreadPool();
List<Future<Boolean>> results = threadPool.invokeAll(tests);
threadPool.shutdown(); // ******* add this! *********
这应该有助于在所有 Callable 完成其操作后关闭 threadPool。
我制作了一个程序来检查完成的 9x9 数独矩阵是否正确。我想创建同时检查行、列和区域的线程,以查看数字 1-9 是否出现在其中。我不熟悉使用 Callable 和 lambda。到目前为止,这是我的代码:
public class Sudoku {
public boolean testBoard(int[][] board) throws InterruptedException, ExecutionException {
List<Callable<Boolean>> tests = new ArrayList<>();
tests.add(() -> testCols(board));
tests.add(() -> testRegions(board));
tests.add(() -> testRows(board));
tests.add(() -> testSize(board));
/*Maybe store this threadPool in a field so you dont create it everytime*/
ExecutorService threadPool = Executors.newCachedThreadPool();
List<Future<Boolean>> results = threadPool.invokeAll(tests);
for (Future<Boolean> future : results) {
if (!Boolean.TRUE.equals(future.get())) {
return false;
}
}
return true;
}
// check that the board is 9 x 9
boolean testSize(int[][] board) {
if (board.length != 9) {
return false;
}
for (int i = 0; i < board.length; i++) {
if (board[i].length != 9) {
return false;
} else;
}
return true;
}
// check that the digits 1-9 each appear exactly once in the given array
boolean checkDigits(int[] array) {
if (array.length != 9) {
return false;
}
int[] counts = new int[10];
for (int i = 0; i
< array.length; i++) {
// invalid number
if (array[i] < 1 || array[i] > 9) {
return false;
}
// we have already seen this number
if (counts[array[i]] > 0) {
return false;
}
counts[array[i]]++;
}
return true;
}
// return true if all rows are correct
boolean testRows(int[][] board) {
for (int i = 0; i < board.length; i++) {
if (!checkDigits(board[i])) {
return false;
}
}
return true;
}
// return true if all columns are correct
boolean testCols(int[][] board) {
int[] tmp = new int[board.length];
for (int col = 0; col < board.length; col++) {
// fill a temp array with every element of the column
for (int row = 0; row < board.length; row++) {
tmp[row]
= board[row][col];
}
// check to make sure it has all the right digits
if (!checkDigits(tmp)) {
return false;
}
}
return true;
}
// return true if every region is correct
boolean testRegions(int[][] board) {
//loop through each region, passing the indices of the upper-left corner to the next method
//note that we increment row and column counters by 3 here
for (int row = 0; row < board.length; row += 3) {
for (int col = 0; col
< board.length; col += 3) {
if (!testRegion(board, row, col)) {
return false;
}
}
}
return true;
}
// test a specific region, given the upper left corner
boolean testRegion(int[][] board, int startRow, int startCol) {
int[] tmp = new int[board.length];
// fill a temporary array with every element of the region
int index = 0;
for (int row = startRow; row < startRow + 3; row++) {
for (int col = startCol; col < startCol + 3; col++) {
tmp[index]
= board[row][col];
index++;
}
}
// check if we have all of the right digits in the region
return checkDigits(tmp);
}
}
public class TestPuzzle {
public static void testpuzzle() throws FileNotFoundException, InterruptedException, ExecutionException{
Sudoku sudoku = new Sudoku();
String fileName = "SudokuRight.txt";//This is for the print statment
Scanner inputStream = null;
String[] line;
System.out.println("The file " + fileName + " contains the following sudoku puzzle:\n");
inputStream = new Scanner(new File("C:\Users\username\Documents\NetBeansProjects\Sudoku\SudokuRight.txt"));
int[][] puzzle = new int[9][9];
int row = 0;
while (inputStream.hasNextLine()) {
line = inputStream.nextLine().split(",");
for (int i = 0; i < 9; i++) {
puzzle[row][i] = Integer.parseInt(line[i]);
}
row++;
}
for (int i = 0; i < 9; i++) {
System.out.println(Arrays.toString(puzzle[i]));
}
boolean result = sudoku.testBoard(puzzle);
System.out.println("Result: " + result);
if (result == true) {
System.out.println("This sudoku solution IS valid!");
} else if (result == false) {
System.out.println("This sudoku solution IS NOT valid!");
}
}
}
public class Main {
//This is the main method to check the validity of sudoku puzzles
public static void main(String[] args) throws FileNotFoundException, InterruptedException, ExecutionException {
TestPuzzle.testpuzzle();
}
}
有人试图教我如何使用 callable 和 lambda,但我仍然有点困惑。我的代码现在 运行 正确,但是,在 NetBeans 中打印出结果后,它会继续 运行 直到我手动终止它。我不确定为什么?我以为我的代码中必须有这样的语句块:
Callable<Boolean> callable = () -> Boolean.valueOf(testCols(board));
Callable<Boolean> callable = () -> Boolean.valueOf(testRows(board));
Callable<Boolean> callable = () -> Boolean.valueOf(testRegions(board));
Callable<Boolean> callable = () -> Boolean.valueOf(testSize(board));
但是我不确定将这些行放在哪里?我不能将它们放入构造函数中,因为 "board" 尚未初始化。我确定这是一个简单的修复,因为我是新手,所以我被卡住了。有什么帮助吗?
根据我的评论,我认为您的问题是您在向执行程序服务添加所有 Callable 并调用它们之后没有调用 shutdown()
。我建议你这样做:
ExecutorService threadPool = Executors.newCachedThreadPool();
List<Future<Boolean>> results = threadPool.invokeAll(tests);
threadPool.shutdown(); // ******* add this! *********
这应该有助于在所有 Callable 完成其操作后关闭 threadPool。