繁体   English   中英

多重阅读是否正确使用等待和通知

[英]Multihreading do I correctly use wait and notify

我写了一个解决哲学家问题的方法。 它正在运行,但在绝不打印wait()之后,我在控制台上获得了正确的输出,但是println() 请告诉我为什么。 我在代码中指出了这一点。

该解决方案的含义类似于 http://en.wikipedia.org/wiki/Dining_philosophers_problem#Resource_hierarchy_solution

public class Philosopher extends Thread {
    String name;
    // boolean je, czeka;
    int nr;
    Fork left, right;

    public Philosopher(String name, int nr, Fork left, Fork right) {
        this.nr = nr;
        this.name = name;
        this.left = left;
        this.right = right;
        System.out.println("NR " + nr +"  "+ left + " " + right);
    }

    public void run() {
        // while(true){
        try {
            Fork minF = Fork.min(left, right);
            Fork maxF = Fork.max(left, right);

            synchronized (minF) {
                if (!minF.used) {
                    minF.used = true;
                    System.out.println("P" + nr + " took fork " + minF);
                } else {
                    minF.wait();
                    minF.used = true;
                    System.out.println("I waited and took fork " + minF); //why it is never PRINTEDDD???
                }
                synchronized (maxF) {
                    if (!maxF.used) {
                        maxF.used = true;
                        System.out.println("P" + nr + " took fork "
                                + maxF);
                    } else {
                        maxF.wait();
                        maxF.used = true;
                        System.out.println("I waited and took fork "+ maxF); //why it is never PRINTEDDD??
                    }
                    System.out.println("I am eating right now" + this);
                    eating();
                    System.out.println("P" + nr
                            + " I have eaten  I am giving back the forks");
                    minF.used = false;
                    System.out.println("P" + nr +  " NOTIFY fork" + minF);
                    minF.notify();
                    maxF.used = false;
                    System.out.println("P" + nr + " NOTIFY fork" + maxF);
                    maxF.notify();
                }
            }
        } catch (Exception e) {
        }

        // }
    }

    public void eating() throws InterruptedException {
        int time = (int) (Math.random() * 2000);

        for (int i = 0; i < 5; i++) {
            System.out.println("P" + nr + " " + i);
            Thread.sleep(time / 5);
        }
    }

    public String toString() {
        return "Philosopher " + nr;
    }

    public static void startPhilosophers(Philosopher[] f) {
        for (int i = f.length - 1; i >= 0; i--) {
            f[i].start();
        }
    }

    public static void main(String[] args) {
        Fork[] t = Fork.getArrayOfForks();
        Philosopher[] f = { new Philosopher("philosopher 1", 1, t[0], t[4]),
                new Philosopher("philosopher 2", 2, t[1], t[0]),
                new Philosopher("philosopher 3", 3, t[2], t[1]),
                new Philosopher("philosopher 4", 4, t[3], t[2]),
                new Philosopher("philosopher 5", 5, t[4], t[3]), };
        startPhilosophers(f);

    }

}

public class Fork {
    boolean used;
    int nr;

    public Fork(boolean used, int nr) {
        this.used = used;
        this.nr = nr;
    }

    @Override
    public String toString() {
        return "F" + nr;
    }
    public static Fork min(Fork l, Fork p){
        if(l.nr < p.nr)
            return l;
        return p;
    }


    public static Fork max(Fork l, Fork p){
        if(l.nr > p.nr)
            return l;
        return p;
    }
    public static Fork[] getArrayOfForks() {
        Fork[] t = new Fork[5];
        for (int i = 0; i < t.length; i++) {
            t[i] = new Fork(false, (i + 1));
        }
        return t;
    }
}

EXAMPLE output
NR 1  F1 F5
NR 2  F2 F1
NR 3  F3 F2
NR 4  F4 F3
NR 5  F5 F4
P5 took fork F4
P5 took fork F5
I am eating right nowPhilosopher 5
P4 took fork F3
P5 0
P2 took fork F1
P2 took fork F2
I am eating right nowPhilosopher 2
P2 0
P5 1
P2 1
P5 2
P2 2
P5 3
P2 3
P5 4
P2 4
P5 I have eaten  I am giving back the forks
P5 NOTIFY forkF4
P5 NOTIFY forkF5
P4 took fork F4
I am eating right nowPhilosopher 4
P4 0
P2 I have eaten  I am giving back the forks
P2 NOTIFY forkF1
P2 NOTIFY forkF2
P3 took fork F2
P1 took fork F1
P1 took fork F5
I am eating right nowPhilosopher 1
P1 0
P1 1
P4 1
P1 2
P4 2
P1 3
P4 3
P1 4
P4 4
P1 I have eaten  I am giving back the forks
P1 NOTIFY forkF1
P1 NOTIFY forkF5
P4 I have eaten  I am giving back the forks
P4 NOTIFY forkF3
P4 NOTIFY forkF4
P3 took fork F3
I am eating right nowPhilosopher 3
P3 0
P3 1
P3 2
P3 3
P3 4
P3 I have eaten  I am giving back the forks
P3 NOTIFY forkF2
P3 NOTIFY forkF3
synchronized (minF) {
    if (!minF.used) { // always
        minF.used = true;
    }
    ...
    minF.used = false;
    minF.notify();
}

您正在同步这些分叉,以便该哲学家在检查它们是否正在使用时已经对其进行了锁定。 哲学家将fork.used设置为true,但在离开同步块并释放锁之前将其设置为false。

编辑:根据要求,更新版本的代码。 如果您已经使用同步块,则无需自己进行管理:

synchronized (minF) {
    synchronized (maxF) {
        System.out.println("I am eating right now" + this);
        eating();
        System.out.println("P" + nr
            + " I have eaten  I am giving back the forks");
    }
}

如果要显式地写出来,我将使用java.util.concurrent类,并从Semaphore扩展Fork。 然后,您的代码如下所示:

叉子:

public class Fork extends Semaphore {
int nr;

public Fork(int nr) {
    super(1); // can be handed out to only one person at a time
    this.nr = nr;
}
...

和哲学家:

minF.acquire();
maxF.acquire();
System.out.println("I am eating right now" + this);
eating();
System.out.println("P" + nr
    + " I have eaten  I am giving back the forks");
maxF.release();
minF.release();

flup已经回答了您的问题,但是移动同步块还不够; 如果yu想要将您used标志与waitnotify一起使用,则需要循环检查正在wait的条件,因为即使没有notifywait也会返回。

一种解决方案可能是:

public class Demo
{

    public static class Philosopher
        extends Thread
    {

        String name;

        int nr;

        Fork left, right;


        public Philosopher( String name, int nr, Fork left, Fork right )
        {
            this.nr = nr;
            this.name = name;
            this.left = left;
            this.right = right;
            System.out.println( "NR " + nr + "  " + left + " " + right );
        }


        @Override
        public void run()
        {
            // while ( true )
            try {
                Fork minF = Fork.min( left, right );
                Fork maxF = Fork.max( left, right );

                synchronized ( minF ) {
                    if ( ! minF.used ) {
                        minF.used = true;
                        System.out.println( "P" + nr + " took fork " + minF );
                    } else {
                        while ( minF.used )
                            // <- YOU NEED TO CHECK THIS IN A LOOP
                            minF.wait();
                        minF.used = true;
                        System.out.println( "I waited and took fork " + minF ); // why it is never PRINTEDDD???
                    }
                }
                synchronized ( maxF ) {
                    if ( ! maxF.used ) {
                        maxF.used = true;
                        System.out.println( "P" + nr + " took fork " + maxF );
                    } else {
                        while ( maxF.used )
                            // <- YOU NEED TO CHECK THIS IN A LOOP
                            maxF.wait();
                        maxF.used = true;
                        System.out.println( "I waited and took fork " + maxF ); // why it is never PRINTEDDD??
                    }
                }

                System.out.println( "I am eating right now" + this );
                eating();
                System.out.println( "P" + nr + " I have eaten  I am giving back the forks" );

                synchronized ( minF ) {
                    minF.used = false;
                    System.out.println( "P" + nr + " NOTIFY fork" + minF );
                    minF.notify();
                }

                synchronized ( maxF ) {
                    maxF.used = false;
                    System.out.println( "P" + nr + " NOTIFY fork" + maxF );
                    maxF.notify();
                }
            } catch ( Exception e ) {
                // ignore
            }
        }


        public void eating()
            throws InterruptedException
        {
            int time = (int) ( Math.random() * 2000 );

            for ( int i = 0; i < 5; i ++ ) {
                System.out.println( "P" + nr + " " + i );
                Thread.sleep( time / 5 );
            }
        }


        public String toString()
        {
            return "Philosopher " + nr;
        }


        public static void startPhilosophers( Philosopher[] f )
        {
            for ( int i = f.length - 1; i >= 0; i -- ) {
                f[ i ].start();
            }
        }

    }

    public static class Fork
    {

        boolean used;

        int nr;


        public Fork( boolean used, int nr )
        {
            this.used = used;
            this.nr = nr;
        }


        @Override
        public String toString()
        {
            return "F" + nr;
        }


        public static Fork min( Fork l, Fork p )
        {
            if ( l.nr < p.nr )
                return l;
            return p;
        }


        public static Fork max( Fork l, Fork p )
        {
            if ( l.nr > p.nr )
                return l;
            return p;
        }


        public static Fork[] getArrayOfForks()
        {
            Fork[] t = new Fork[ 5 ];
            for ( int i = 0; i < t.length; i ++ ) {
                t[ i ] = new Fork( false, ( i + 1 ) );
            }
            return t;
        }
    }


    public static void main( String[] args )
    {
        Fork[] t = Fork.getArrayOfForks();
        Philosopher[] f =
            { new Philosopher( "philosopher 1", 1, t[ 0 ], t[ 4 ] ), new Philosopher( "philosopher 2", 2, t[ 1 ], t[ 0 ] ),
                new Philosopher( "philosopher 3", 3, t[ 2 ], t[ 1 ] ), new Philosopher( "philosopher 4", 4, t[ 3 ], t[ 2 ] ),
                new Philosopher( "philosopher 5", 5, t[ 4 ], t[ 3 ] ), };
        Philosopher.startPhilosophers( f );
    }

}

但是,请务必理解,在此示例中,您使事情变得过于复杂。 当您在锁上下订单时,可以摆脱used并简化此过程:

public class Demo2
{

    public static class Philosopher
        extends Thread
    {

        String name;

        int nr;

        Fork left, right;


        public Philosopher( String name, int nr, Fork left, Fork right )
        {
            this.nr = nr;
            this.name = name;
            this.left = left;
            this.right = right;
            System.out.println( "NR " + nr + "  " + left + " " + right );
        }


        @Override
        public void run()
        {
            // while ( true )
            try {
                Fork minF = Fork.min( left, right );
                Fork maxF = Fork.max( left, right );

                synchronized ( minF ) {
                    synchronized ( maxF ) {
                        System.out.println( "I am eating right now" + this );
                        eating();
                        System.out.println( "P" + nr + " I have eaten  I am giving back the forks" );
                    }
                }
            } catch ( Exception e ) {
                // ignore
            }
        }


        public void eating()
            throws InterruptedException
        {
            int time = (int) ( Math.random() * 2000 );

            for ( int i = 0; i < 5; i ++ ) {
                System.out.println( "P" + nr + " " + i );
                Thread.sleep( time / 5 );
            }
        }


        public String toString()
        {
            return "Philosopher " + nr;
        }


        public static void startPhilosophers( Philosopher[] f )
        {
            for ( int i = f.length - 1; i >= 0; i -- ) {
                f[ i ].start();
            }
        }

    }

    public static class Fork
    {

        int nr;


        public Fork( int nr )
        {
            this.nr = nr;
        }


        @Override
        public String toString()
        {
            return "F" + nr;
        }


        public static Fork min( Fork l, Fork p )
        {
            if ( l.nr < p.nr )
                return l;
            return p;
        }


        public static Fork max( Fork l, Fork p )
        {
            if ( l.nr > p.nr )
                return l;
            return p;
        }


        public static Fork[] getArrayOfForks()
        {
            Fork[] t = new Fork[ 5 ];
            for ( int i = 0; i < t.length; i ++ ) {
                t[ i ] = new Fork( i + 1 );
            }
            return t;
        }
    }


    public static void main( String[] args )
    {
        Fork[] t = Fork.getArrayOfForks();
        Philosopher[] f =
            { new Philosopher( "philosopher 1", 1, t[ 0 ], t[ 4 ] ), new Philosopher( "philosopher 2", 2, t[ 1 ], t[ 0 ] ),
                new Philosopher( "philosopher 3", 3, t[ 2 ], t[ 1 ] ), new Philosopher( "philosopher 4", 4, t[ 3 ], t[ 2 ] ),
                new Philosopher( "philosopher 5", 5, t[ 4 ], t[ 3 ] ), };
        Philosopher.startPhilosophers( f );
    }

}

在您的代码中,总是在getArrayOfForks()方法中将Fork-> used属性初始化为false,因此将始终在每个同步块上的wait()处于else条件的情况下执行if条件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM