同步方法不起作用但同步块起作用,为什么?

Synchronized method does not work but synchronized block does, why?

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();

}

这是驱动调用的class:

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();

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

我可以在另一个程序中使用同步方法,有 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();

    }
}

你好class会叫咖啡class:

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;
    }
}

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

上的锁

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

获取 class 上的锁意味着两个线程都在尝试获取相同的锁。为了使锁定工作,两个线程必须使用相同的锁。

在第二个例子中,Coffee 对象被两个线程共享,并且两个线程都试图获取 Coffee 对象上的同一个锁。这意味着获得锁的第二个线程必须阻塞,直到第一个线程释放锁,锁定成功使线程退出,直到第一个线程完成。

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