进程的锁详解版权声明

原创
小哥 3年前 (2022-10-28) 阅读数 86 #大杂烩

Java 中的每个对象在线程访问时都有一个锁synchronized 当方法和代码块的时候,就会获得锁,这也可以理解为锁定对象。锁同时可用,并且只能由一个线程访问。如果一个线程正在访问对象锁,而另一个线程正在访问该锁,则该线程需要等待占用该锁的线程释放该对象锁并进入阻塞状态。当执行完成时synchronized方法或代码块,则线程释放对象锁。
当线程通过时 synchronized 在该方法或代码块获得对象锁之后,任何其他线程都无法访问该对象。synchronized方法或代码块,但可以访问非synchronized方法或代码块。
如果添加到静态方法synchronized 或添加对静态变量的修改。synchronized 块,则这一次您将获得类对象的锁。(class对象)
当线程进入休眠状态时,对象锁不会被释放。
对象锁可以理解为资源。线程使用此资源后,将释放此资源供其他线程使用。

线程中的wait() 与 锁的关系
让我们先来看一段代码:

/**

  • 计算并输出由其他线程锁计算的数据
  • */
    public class ThreadA {
    public static void main(String[] args) throws InterruptedException{
    ThreadB b = new ThreadB();
    //启动计算线程
    b.start(); (原文放在这个位置,但这将导致b线程run该方法执行速度较快,建议放在下面synchronized 在代码块中)
    //线程A拥有b对象上的锁。线程,以便调用。wait()或notify()方法,则该线程必须是该对象锁的所有者。
    synchronized (b) {
    System.out.println("等待对象b完成计算..。");
    //当前线程A等待
    b.wait();
    System.out.println("b对象计算的总和为:" + b.total);
    }
    }
    }

/**

  • 计算1+2+3 ... +100的和
  • */
    class ThreadB extends Thread {
    int total;

public void run() {
synchronized (this) {
for (int i = 0; i < 101; i++) {
total += i;
}
//(已完成)唤醒在此对象监视器上等待的单个线程,在本例中为线程。A被唤醒
notify();
System.out.println("计算完成");
}
}
}

执行结果:

等待对象b完成计算..。
计算完成
b对象计算的总和为:5050

如果我们愿意的话b.wait()去掉它吗?结果如下:

等待对象b完成计算..。
b对象计算的总和为:0
计算完成

上述结果表明,当移除b.wait()何时,新启动的线程ThreadB与主线程ThreadA它是单独执行的,没有线程在等待。

我们想要的效果是,当线程ThreadB完成计算后,获取计算结果。所以它的用途b.wait()让主线程等待。

那为什么要用它呢b.wait(),而不是Thread.currentThread.wait(),还是别的什么?

如果我们愿意的话b.wait()替换成Thread.currentThread.wait(),将得到以下结果:

Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at pa.com.thread.ThreadA.main(ThreadA.java:18)
等待对象b完成计算..。
计算完成

要替换的代码Thread.currentThread.wait()看起来它应该和我们预期的一样正确,让当前线程处于等待状态,让其他线程首先执行。

我们忽略了一个非常重要的问题:线程和锁是密不可分的,线程同步、等待和唤醒都离不开对象锁。

线程ThreadA持有对象b我们将使用该锁让线程释放该锁,以便其他线程可以获取该锁。

从我们的程序来分析是:线程。ThreadA首先按住锁定对象b,然后调用b.wait()释放对象锁,线程ThreadB争取对象锁定b,从而执行run()该方法中的计算在计算完成后使用。notify()唤醒主线程ThreadA,ThreadA能够继续执行,这产生了我们预期的结果。

(之所以ThreadB对象锁也是b,是因为synchronized(this)中的this指向ISThreadB的实例b)

Thread.currentThread.wait()调用是当前的线程对象(即主线程)。ThreadA)的wait()方法,则为当前线程对象。ThreadA它没有被锁定,它只是获得对象锁定。b。我从来没有见过这样的调用,通常使用Lock对象。wait(),在这种情况下b.wait()

顺便说一句,我们来谈谈这件事。wait()与sleep()的区别。

如果我们愿意的话b.wait()换成Thread.sleep(1000),将显示以下结果:

等待对象b完成计算..。
b对象计算的总和为:0
计算完成

从执行结果可以看出,Thread.sleep(1000)只要让主线程ThreadA睡眠了1秒,并且不释放对象锁,因此在主线程中。ThreadA在睡眠中,ThreadB无法获取对象锁,并且无法执行。

因此,我们还得出了以下结论:

wait()方法是让线程释放对象锁,让其他线程获得锁,然后在其他线程整体唤醒时进行优先执行。wait()中的线程 或者 在获得对象锁的线程已经释放对象锁之后,wait()中的线程只会再次获得对象锁以执行。

sleep()方法是让线程休眠。此时,对象锁定不会被释放。其他想要获得休眠线程的对象锁的线程无法获得对应的对象锁,因此不能在它前面仓促执行。

补:

wait、notify和notifyAll方法是Object类的final native方法。因此,这些方法不能用被子重写,Object类是所有类的超类,因此程序中有三种形式的调用。wait等方法。

wait();//方式1:
this.wait();//方式2:
super.wait();//方式3
void wait()
使线程进入等待状态,直到它被另一个线程传递。notify()或者notifyAll觉醒。此方法只能在同步方法中调用。如果当前线程不是锁的持有者,则该方法引发IllegalMonitorStateException异常。

————————————————
版权声明:本文是CSDN博主《程序羊的修养》原文如下CC 4.0 BY-SA版权协议,转载请附上原始来源链接和本声明。
原始链接:https://blog.csdn.net/u012102536/article/details/71108000

版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除