线程中的wait() 与 锁的关系

我们先看一段代码:

/**
* 计算输出其他线程锁计算的数据
*
*/
public class ThreadA {
    public static void main(String[] args) throws InterruptedException{
        ThreadB b = new ThreadB();
        //启动计算线程
        b.start();
        //线程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指向的就是ThreadB的实例b)

Thread.currentThread.wait()调用的是当前线程对象(即主线程ThreadA)的wait()方法,当前线程对象ThreadA是没有被加锁的,它只是获取了对象锁b。我基本没有看到过这样的调用,一般使用的是锁对象的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异常。

时间: 2024-10-14 02:40:53

线程中的wait() 与 锁的关系的相关文章

C++线程中的几种锁

线程之间的锁有:互斥锁.条件锁.自旋锁.读写锁.递归锁.一般而言,锁的功能越强大,性能就会越低. 1.互斥锁 互斥锁用于控制多个线程对他们之间共享资源互斥访问的一个信号量.也就是说是为了避免多个线程在某一时刻同时操作一个共享资源.例如线程池中的有多个空闲线程和一个任务队列.任何是一个线程都要使用互斥锁互斥访问任务队列,以避免多个线程同时访问任务队列以发生错乱. 在某一时刻,只有一个线程可以获取互斥锁,在释放互斥锁之前其他线程都不能获取该互斥锁.如果其他线程想要获取这个互斥锁,那么这个线程只能以阻

线程中锁的使用---Python

1.普通同步 用threading.Lock()创建锁,用acquire()申请锁,每次只有一个线程获得锁,其他线程必须等此线程release()后才能获得锁 RLock允许在同一线程中被多次acquire.而Lock却不允许这种情况.注意:如果使用RLock,那么acquire和release必须成对出现,即同一线程中调用了n次acquire,必须调用n次的release才能真正释放所占用的琐 2.条件同步 Condition(条件变量)通常与一个锁关联.需要在多个Contidion中共享一个

Objective-C中不同方式实现锁(二)-11-多线程

1 Objective-C中不同方式实现锁(二) 2 3 在上一文中,我们已经讨论过用Objective-C锁几种实现(跳转地址),也用代码实际的演示了如何通过构建一个互斥锁来实现多线程的资源共享及线程安全,今天我们继续讨论锁的一些高级用法. 4 5 1.NSRecursiveLock递归锁 6 7 平时我们在代码中使用锁的时候,最容易犯的一个错误就是造成死锁,而容易造成死锁的一种情形就是在递归或循环中,如下代码: 8 9 1 10 2 11 3 12 4 13 5 14 6 15 7 16 8

Objective-C中不同方式实现锁(一)-12-多线程

Objective-C中不同方式实现锁(一) 为什么需要使用锁,当然熟悉多线程的你,自然不会对它觉得陌生. 那你在代码中是否很好的使用了锁的机制呢?你又知道几种实现锁的方法呢? 今天一起来探讨一下Objective-C中几种不同方式实现的锁,在这之前我们先构建一个测试用的类,假想它是我们的一个共享资源,method1与method2是互斥的,代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 @implementation TestObj - (void)method1 {

JAVA线程池中队列与池大小的关系

JAVA线程中对于线程池(ThreadPoolExecutor)中队列,池大小,核心线程的关系写出自己的理解: 1:核心线程:简单来讲就是线程池中能否允许同时并发运行的线程的数量 2:线程池大小:线程池中最多能够容纳的线程的数量. 3:队列:对提交过来的任务的处理模式. 对于线程池与队列的交互有个原则: 如果队列发过来的任务,发现线程池中正在运行的线程的数量小于核心线程,则立即创建新的线程,无需进入队列等待.如果正在运行的线程等于或者大于核心线程,则必须参考提交的任务能否加入队列中去. 1:提交

Python进阶(3)_进程与线程中的lock(互斥锁、递归锁、信号量)

1.同步锁 (Lock) 当各个线程需要访问一个公共资源时,会出现数据紊乱 例如: 1 import threading,time 2 def sub(): 3 global num #对全局变量进行操作 4 5 temp=num 6 time.sleep(0.001) #模拟线程执行中出现I/o延迟等 7 num=temp-1 #所有线程对全局变量进行减一 8 9 time.sleep(1) 10 11 num=100 12 l=[] 13 14 for i in range(100): 15

Java线程中锁的问题

Java线程中锁的问题: 同步代码块的锁是自己定义的类:object obj = new object 同步方法的锁是this 静态同步方法的锁是类名.class

JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制

JAVA之旅(十四)--静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是class对象 我们在上节验证了同步函数的锁是this,但是对于静态同步函数,你又知道多少呢? 我们做一个这样的小实验,我们给show方法加上static关键字去修饰 private static synchronized void show() { if (tick > 0) { try { Thread

web开发中的两把锁之数据库锁:(高并发--乐观锁、悲观锁)

这篇文章讲了 1.同步异步概念(消去很多疑惑),同步就是一件事一件事的做:sychronized就是保证线程一个一个的执行. 2.我们需要明白,锁机制有两个层面,一种是代码层次上的,如Java中的同步锁,典型的就是同步关键字synchronized ( 线    程级别的).另一个就是数据库层次上的,比较典型的就是悲观锁和乐观锁. 3.常见并发同步案例分析   附原文链接 http://www.cnblogs.com/xiohao/p/4385508.html 对于我们开发的网站,如果网站的访问