【问题标题】:Synchronized method does not work but synchronized block does, why?同步方法不起作用,但同步块起作用,为什么?
【发布时间】:2022-01-13 12:53:59
【问题描述】:
public class driver{


public static void main(String[] args) {
    PrintNum firstObjectForThread = new PrintNum(0);  // the argument is not used, ignore it
    firstObjectForThread.startNewThread();

    PrintNum secondObjectForThread = new PrintNum(0);
    secondObjectForThread.startNewThread();

}

这是驱动程序调用的类:

public class ClassName implements Runnable{

int variableForUpdate;
private Thread t;
private static ArrayList<Integer> intArray;

public ClassName(int variableForUpdate) {
    super();
    this.intArray = new ArrayList<Integer>();
    this.variableForUpdate = variableForUpdate;
    for (int i = 0; i < 30 ; i++) {
        this.intArray.add(i);
    }
}

@Override
public void run() {
    runThisWhenThreadStarts();
}


private synchronized void runThisWhenThreadStarts() {
    System.out.println("Started");
    for (int i = 0; i < 30; i++) {
        System.out.println(intArray.get(i));
    }
}

public void startNewThread() {
    t = new Thread(this);
    t.start();
}

}

如果我使用下面的块同步,输出是同步的:

private void runThisWhenThreadStarts() {
    synchronized (ClassName.class) {
        System.out.println("Started");
        for (int i = 0; i < 30; i++) {
            System.out.println(intArray.get(i));
        }
    }
}

我已经解决这个问题好几个小时了,但无法弄清楚......有人可以解释一下吗? 我还注意到,如果我使用同一个对象调用 startNewThread(),同步将起作用。但我不明白为什么。

    PrintNum firstObjectForThread = new PrintNum(0);  // the argument is not used, ignore it
    firstObjectForThread.startNewThread();
    firstObjectForThread.startNewThread();

我想使用来自同一类的两个不同对象,而不是一个对象调用该方法两次(上述解决方法)。

我可以在另一个程序中使用同步方法,有 2 个不同的实例(get 和 put):

public class Hello extends Thread {
    int x;
    Coffee x1;
    int threadno;

    Hello(int x, Coffee x1) {
        this.x = x;
        threadno = x;
        this.x1 = x1;
    }

    public void run() {
        switch (x) {
        case 0:
            System.out.println("Start thread " + threadno + " Get");
            break;
        case 1:
            System.out.println("Start thread " + threadno + " Put");
            break;
        }
        ops();
        System.out.println("Stopping thread " + threadno);

    }

    public void ops() {
        x1.get();
    }

    public static void main(String[] args) {
        Coffee c1 = new Coffee();
        Hello get = new Hello(0, c1);
        Hello put = new Hello(0, c1);
        get.start();
        put.start();

    }
}

Hello 类将调用咖啡类:

class Coffee {
    boolean available = false; // indicating there nothing to get.
    // waiting on each other.
    int contents = 55;

    public synchronized int get() {
        System.out.println("Entering Get method " + contents);
        for (int i = 0; i < 30; i++) {
            System.out.println(i);
            }
        return contents;
    }
}

【问题讨论】:

    标签: java multithreading synchronization synchronized


    【解决方案1】:

    在第一个示例中,该方法获取调用该方法的对象实例上的锁。该块不这样做,而是获取类上的锁。

    获取实例上的锁对另一个线程没有影响,它是一个不同的对象。两个线程都在获取自己的锁,这是没有用的。两个线程都不会被阻止做任何事情。

    获取类上的锁意味着两个线程都试图获取相同的锁。为了使锁定起作用,两个线程必须使用相同的锁定。

    在第二个示例中,Coffee 对象由两个线程共享,并且两个线程都试图在 Coffee 对象上获取相同的锁。这意味着获得锁的第二个线程必须阻塞,直到第一个线程释放锁为止,成功锁定会使线程保持在外,直到第一个线程完成。

    要了解同步,请跟踪正在获取的锁。

    【讨论】:

    • 谢谢。我也是这么想的。但是我有另一个程序实际上可以使用与同一类的 2 个对象进行同步,同步将起作用。你知道为什么吗?我在我的问题中发布了代码。
    • @IHaveAQuestion:已更新
    • 感谢您的快速回复。为什么两个 Hello 对象共享同一个 Coffee 对象?当 Hello 对象被实例化时,它应该通过“Coffee c1 = new Coffee();”创建一个新的 Coffee 对象?编辑:啊,我明白了!现在一切都说得通了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-30
    • 1970-01-01
    • 2012-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多