java - 使用 while 循环强制代码等待条件需要 thread.sleep()

标签 java multithreading

我创建了一个程序,将线性搜索(搜索 -1)划分为 4 个单独的线程。

public class main {

    static boolean found = false;

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        int threadCount = 4; //amount of threads to use
        Random rand = new Random();
        Searcher[] s_arr = new Searcher[threadCount]; //array of threads


        int[] arr = new int[10000]; //array to search through
        for (int i = 0; i < arr.length; i++) //randomizing #'s in array
            arr[i] = (int) (rand.nextFloat() * 1000);

        int randIndex = rand.nextInt(arr.length); //choose random index

        arr[randIndex] = -1; //set random index to = -1

        for (int i = 0; i < threadCount; i++) { //
            s_arr[i] = new Searcher(Arrays.copyOfRange(arr, i * (arr.length/threadCount), (i+1) * (arr.length/threadCount)), 
                    (int) (i), i); //assign subarray for this thread to search through
            System.out.println(s_arr[i].wait);
            s_arr[i].start(); 
        }


        //CODE IN QUESTION HERE ----------------------------
        //while (!found) ;

        while (!found) //wait until value is found
        {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
//-----------------------------------------------------------





        System.out.println("found!");

        for (int i = 0; i < threadCount; i++) {
            try {
                s_arr[i].join(); //wait for the threads in order before continuing
                System.out.println("Thread ["+i+"] completed");
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println("All threads stopped, program complete.");
    }

}

public class Searcher extends Thread {

    int[] arr;
    int wait;
    int index;

    public Searcher(int[] arr, int wait, int i) {
        this.arr = arr;
        this.wait = wait;
        this.index = i;
    }

    @Override
    public void run() {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == -1) {
                System.out.println("["+index+"] -1 Found at index: "+i);
                main.found = true;
                break;
            }
            if (main.found) break;
            //purposely slow down this thread
            try {
                Thread.sleep(wait);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println("["+index+"] has stopped");

    }

}

我已经标记出有问题的代码,在使用第一个(注释掉的)while 循环时,程序不会超出该点,但是如果我切换并使用它正下方的另一个 while 循环(那个这会强制每个迭代器等待 1 毫秒)程序运行良好。

这是为什么,是否有更有效/实用的方法来完成此任务?

最佳答案

Repeatedly reading a non-volatile field within the condition of an empty loop statement may result in an infinite loop, since a compiler optimization may move this field access out of the loop.

来源:help.semmle.com

如果将 static boolean found = false; 替换为 volatile static boolean found = false;,第一个循环会起作用,但我不推荐这样做,因为它会浪费你的CPU时间。 您应该考虑使用 waitnotify

static boolean found 下方,添加 static final Object lock = new Object(); 并将两个 while 循环替换为

try {
    synchronized (lock) {
        // we will wait here until we get notified
        lock.wait();
    }
} catch (InterruptedException e) {
    e.printStackTrace();
}

还在main.found = true之后添加

synchronized (main.lock) {
    main.lock.notify();
}

最后,你的代码应该是这样的

public class main {

    static boolean found;
    static final Object lock = new Object();

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        int threadCount = 4; //amount of threads to use
        Random rand = new Random();
        Searcher[] s_arr = new Searcher[threadCount]; //array of threads


        int[] arr = new int[10000]; //array to search through
        for (int i = 0; i < arr.length; i++) //randomizing #'s in array
            arr[i] = (int) (rand.nextFloat() * 1000);

        int randIndex = rand.nextInt(arr.length); //choose random index

        arr[randIndex] = -1; //set random index to = -1

        for (int i = 0; i < threadCount; i++) { //
            s_arr[i] = new Searcher(Arrays.copyOfRange(arr, i * (arr.length/threadCount), (i+1) * (arr.length/threadCount)),
                    (int) (i), i); //assign subarray for this thread to search through
            System.out.println(s_arr[i].wait);
            s_arr[i].start();
        }

        try {
            synchronized (lock) {
                lock.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("found!");

        for (int i = 0; i < threadCount; i++) {
            try {
                s_arr[i].join(); //wait for the threads in order before continuing
                System.out.println("Thread ["+i+"] completed");
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println("All threads stopped, program complete.");
    }

}

class Searcher extends Thread {

    int[] arr;
    int wait;
    int index;

    public Searcher(int[] arr, int wait, int i) {
        this.arr = arr;
        this.wait = wait;
        this.index = i;
    }

    @Override
    public void run() {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == -1) {
                System.out.println("["+index+"] -1 Found at index: "+i);
                main.found = true;
                synchronized (main.lock) {
                    main.lock.notify();
                }
                break;
            }
            if (main.found) break;
            //purposely slow down this thread
            try {
                Thread.sleep(wait);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println("["+index+"] has stopped");

    }

}

关于java - 使用 while 循环强制代码等待条件需要 thread.sleep(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58252656/

相关文章:

ios - AFNetworking 究竟是如何工作的?

java - 什么会导致 Java ScheduleService 无法运行?

java - Hibernate 和 MySQL 超出锁定等待超时(使用 Play Framework )

java - 字段未发送到服务器

java - Spring 相当于 Grails "plugin"(模块化 Spring 应用程序)

java - 无法在运行时调整文本字段的大小

c++ - 英特尔 tbb 任务调度是否适合 DBMS?

java - 如何从字符串中删除摄氏度符号(java)

c++ - 传递给新线程的结构有错误的值

javascript - node.js 非阻塞 POST 请求等待另一个 POST 请求