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

Posted

技术标签:

【中文标题】同步方法不起作用,但同步块起作用,为啥?【英文标题】: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;
    

【问题讨论】:

【参考方案1】:

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

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

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

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

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

【讨论】:

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

以上是关于同步方法不起作用,但同步块起作用,为啥?的主要内容,如果未能解决你的问题,请参考以下文章

为啥控制忙指示灯不起作用

CORS 同步请求在 Firefox 中不起作用

同步数据透视表 - VBA 代码不起作用

排毒--调试同步不起作用

为啥 MR_save 不起作用但 MR_saveNestedContexts 起作用?

kafka-connect 到同步数据库的硬删除事件不起作用或出现错误