Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java自动识别线程死锁并停止执行?_Java_Multithreading_Concurrency_Deadlock - Fatal编程技术网

Java自动识别线程死锁并停止执行?

Java自动识别线程死锁并停止执行?,java,multithreading,concurrency,deadlock,Java,Multithreading,Concurrency,Deadlock,我正在做一个Java项目来模拟 我从基本行为开始,其中每个线程think()、getForks()、eat()和putForks()。因此,没有预防死锁或饥饿(故意的) getForks()方法的工作原理如下: getForks(){ while(forks[rightFork]==0) /*0 means fork is not on the table, so wait*/ print(Thread #id waiting for right fork);

我正在做一个Java项目来模拟

我从基本行为开始,其中每个线程think()、getForks()、eat()和putForks()。因此,没有预防死锁或饥饿(故意的)

getForks()方法的工作原理如下:

getForks(){
    while(forks[rightFork]==0) /*0 means fork is not on the table, so wait*/
         print(Thread #id waiting for right fork);
    forks[rightFork] = 0;
    while(forks[leftFork]==0)
         print(Thread #id waiting for left fork);
    forks[leftFork = 0;
}
我在获取右分支和左分支之间设置了一个sleep(5000),因此程序运行时陷入死锁(每个线程都持有右分支)。然而,出乎意料的是,由于某种原因,一旦执行达到死锁,就会停止执行。我原以为“Thread#id waiting for fork”消息会在死锁期间一直被打印出来,但事实并非如此。一旦达到死锁,就不会再打印消息

有什么线索吗

如果您想查看整个代码,请参见:

public class Philosophers{
    private static final int NUMBER = 3;
    private static final int MIN_SLEEP = 1000;
    private static final int MAX_SLEEP = 6000;
    private static Thread[] threads = new Thread[NUMBER];
    private static int[] forksArray = new int[8];

    private static void start(){
        System.out.println("Simulation started.");

        //Initialize forks array (1 means on the table)
        for(int i=0;i<7;i++)
            forksArray[i] = 1;

        //Create and start individual threads
        for(int i=0;i<NUMBER;i++){
            threads[i] = new Thread(new Philosopher(i));
            threads[i].start();
        }
    }

    public static void main(String[] args){
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                start();
            }
        });
    }

    private static class Philosopher implements Runnable{
        private int id;
        private int leftFork;
        private int rightFork;

        public void run(){
            System.out.println("Thread "+id+" started.");
            while(true){
                think();
                getForks();
                eat();
                putForks();
            }
        }

        public Philosopher(int id){
            this.id = id;
            this.rightFork = id;
            if(id==NUMBER - 1)
                this.leftFork = 0;
            else
                this.leftFork = id + 1;
        }

        public void think(){
            System.out.println("Thread "+id+" thinking...");
            try{
                int sleepInterval = MIN_SLEEP + (int)(Math.random() * ((MAX_SLEEP - MIN_SLEEP) + 1));
                Thread.sleep(sleepInterval);
            }
            catch(Exception e){
                System.out.println(e);
            }
        }

        public void getForks(){
            System.out.println("Thread "+id+" getting forks.");

            //Grab fork on the right
            while(forksArray[rightFork]==0)
                System.out.println("Thread "+id+" waiting for right fork");
            forksArray[rightFork] = 0;  

            try{
            Thread.sleep(5000);
        }   
        catch(Exception e){

        }

            //Grab fork on the left
            while(forksArray[leftFork]==0);
            System.out.println("Thread "+id+" waiting for left fork");
            forksArray[leftFork] = 0;           
        }

        public void eat(){
            System.out.println("Thread "+id+" eating.");
            try{
                Thread.sleep(2000);
            }
            catch(Exception e){
                System.out.println(e);
            }
        }

        public void putForks(){
            System.out.println("Thread "+id+" putting forks down.");
            forksArray[rightFork] = 1;
            forksArray[leftFork] = 1;
        }
    }
}
公共类哲学家{
专用静态最终整数=3;
专用静态最终int MIN_SLEEP=1000;
专用静态最终int MAX_SLEEP=6000;
私有静态线程[]线程=新线程[编号];
私有静态int[]forksArray=newint[8];
私有静态void start(){
System.out.println(“模拟开始”);
//初始化forks数组(表上的1表示)

对于(inti=0;i这不是真正的死锁:您不使用任何锁!它只是一个无限循环

一个问题是您没有使用正确的同步。特别是,编译器可以自由替换:

while (forksArray[leftFork] == 0);
与:

在程序执行过程中,这种情况随时可能发生

只需使您的阵列不稳定:

private static volatile int[] forksArray = new int[8];

但是请注意,将数组标记为volatile只会阻止执行优化-这不足以使代码线程安全。

这不是真正的死锁:您不使用任何锁!它只是一个无限循环

一个问题是您没有使用正确的同步。特别是,编译器可以自由替换:

while (forksArray[leftFork] == 0);
与:

在程序执行过程中,这种情况随时可能发生

只需使您的阵列不稳定:

private static volatile int[] forksArray = new int[8];

应使此问题消失。但是请注意,将数组标记为volatile只会阻止执行优化-这不足以使代码线程安全。

我认为您的问题在于:

while(forksArray[leftFork]==0);
System.out.println("Thread "+id+" waiting for left fork");
while()
后面的;表示它的主体是一个空语句。因此,下一行的
println
仅在循环终止后才会出现


(顺便说一句,这就是为什么人们经常建议始终使用{}for循环,即使它们是单行)

我认为您的问题在于:

while(forksArray[leftFork]==0);
System.out.println("Thread "+id+" waiting for left fork");
while()
后面的;表示它的主体是一个空语句。因此,下一行的
println
仅在循环终止后才会出现



(顺便说一句,这就是为什么人们经常建议始终使用{}for循环,即使它们是单行的)

如果看不到实际代码,就无法判断-您使用锁吗?同步块?@assylias,好了。如果看不到实际代码,就无法判断-您使用锁吗?同步块吗?@assylias,好了。这一行很好:它意味着等待值变为!=0。并且该值从另一行更新Rthread@assylias是的,但问题是为什么没有打印消息。这是因为OP认为
println
是循环的主体,但实际上;,是循环的主体。@Russell Zahniser,你答对了。基本上,没有打印消息是因为额外的“;”。谢谢。那句话很好:是的意味着等待值变为!=0。并且该值从另一个值更新thread@assylias是的,但问题是为什么没有打印消息。这是因为OP认为
println
是循环的主体,但实际上;,是循环的主体。@Russell Zahniser,你搞定了。基本上,我们看到的消息因为额外的“;”而没有打印。谢谢。我的问题不是如何避免陷入死锁(我知道如何为此使用锁)。我的问题是,消息到达该点后,为什么会停止打印。即使编译器替换了您建议的代码,您是否同意在线程一直等待分叉的同时仍应继续打印消息?此外,即使您使用“volatile”使用我上面粘贴的代码,您仍然会遇到死锁。Volatile只告诉您不应将变量放入寄存器中进行优化。@DanielS很抱歉,我引用了错误的循环-请参阅我的编辑。添加Volatile时,我不再观察您提到的行为。使数组变为Volatile不会使修改元素具有volatile语义!您可以使用AtomicIntegerArray来执行此操作。但是,这并不能解决缺乏原子性的问题。@Assylias,我更新了代码以包含睡眠(5000)在得到右叉和左叉之间。加上睡眠,你会看到死锁和消息不再被打印。@jtahlborn我知道-但这足以阻止导致问题的优化。我添加了一个注释来澄清。我的问题不是如何避免陷入死锁(我知道如何使用锁来实现此目的)。我的问题是,消息到达该点后,为什么会停止打印。即使编译器替换了您建议的代码,您是否同意在线程一直等待分叉的同时仍应继续打印消息?此外,即使您使用“volatile”使用我上面粘贴的代码,您仍然会遇到死锁。Volatile只告诉您不应将变量放入寄存器中进行优化。@DanielS很抱歉,我引用了错误的循环-请参阅我的编辑。添加Volatile时,我不再观察您提到的行为。使数组变为Volatile不会使修改元素具有volatile语义!您可以使用Ato