猿问

什么时候应该使用同步方法,什么时候应该在 Java 中使用同步块?

我正在研究如何在 Java 中同步方法和块以避免竞争条件,我试图以两种方式解决一个练习。问题是,如果我尝试使用同步块,一切正常,但使用同步方法会卡住。我认为我可以使用两种方式而没有太大的差异(也许其中一种方式在某些情况下会降低并行性,但我不确定这一点)。我想知道我的代码有什么问题,我想问一下是否有任何情况下最好使用同步块而不是同步方法。


//不工作


import java.util.Random;


class MultiplicationTable extends Thread {

    private Cont obj;

    private int number;

    private Random r;


    public MultiplicationTable(Cont o, int num) {

        obj = o;

        number = num;

        r = new Random();

        start();

    }


    public void run() {


        for (int j = 0; j < 10; j++) {

            for (int i = 0; i < number; i++) {

                obj.incr();

                try {

                    Thread.sleep(100);

                } catch (InterruptedException e) {

                }

            }

            System.out.println(Thread.currentThread().getName() + ": " + obj.getVal());

        }

        try {

            Thread.sleep(r.nextInt(2000));

        } catch (InterruptedException e) {

        }

    }

}


class Cont {

    private int count = 0;

    private boolean available = false;


    public synchronized void incr() {

        while (available) {

            try {

                wait();

            } catch (InterruptedException e) {

                // TODO: handle exception

            }

        }

        available = true;

        count++;

        notifyAll();

    }


    public synchronized int getVal() {

        while (!available) {

            try {

                wait();

            } catch (Exception e) {

                // TODO: handle exception

            }

        }

        available = false;

        notifyAll();

        return count;

    }

}


public class Es3 {

    public static void main(String[] args) {

        Cont obj = new Cont();

        int num = 5;

        MultiplicationTable t1 = new MultiplicationTable(obj, num);

        MultiplicationTable t2 = new MultiplicationTable(obj, num);

    }

}


胡说叔叔
浏览 122回答 2
2回答

慕森王

我不认为这是一个骗局,因为尽管有标题,但实际问题是 OP 的具体实现。代码中有一个错误,这不是方法与块的问题。代码中的错误是您尝试实现锁定机制的地方。在incr()中,您等到available设置为 false,这仅发生在getVal():public synchronized void incr() {&nbsp; &nbsp; while (available) { // <-- bug&nbsp; &nbsp; &nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wait();由于您的循环只调用incr()而不调用getVal(),因此两个线程在第一次调用incr(). (你getVal()最终会调用,但只有在内循环完成之后。两个线程都很好并且到那时卡住了。)解决方案:AtomicInteger没有像这样的奇怪错误。如果您尝试实现某种生产者/消费者机制,那么其中一个并发队列(如ArrayBlockingQueue)是更好的解决方案。

jeck猫

同步方法和块之间的一个显着区别是,同步块通常会减少锁定范围。由于锁定范围与性能成反比,因此只锁定代码的关键部分总是更好。使用同步块的最佳示例之一是 Singleton 模式中的双重检查锁定,getInstance()我们只锁定用于创建 Singleton 实例的代码的关键部分,而不是锁定整个方法。这极大地提高了性能,因为锁定只需要一两次。同步块提供了对锁的精细控制,因为您可以使用任意锁来为关键部分代码提供互斥。另一方面,同步方法总是锁定由 this 关键字表示的当前对象或类级别锁定,如果它的静态同步方法。如果作为参数提供给块的表达式计算为 null,则同步块可以抛出 throw&nbsp;java.lang.NullPointerException,而同步方法则不是这种情况。在同步方法的情况下,线程进入方法时获取锁,离开方法时释放锁,正常或抛出异常。另一方面,在同步块的情况下,线程进入同步块时获取锁,离开同步块时释放。
随时随地看视频慕课网APP

相关分类

Java
我要回答