精华内容
下载资源
问答
  • 本章,会对线程等待/唤醒方法进行介绍。涉及到的内容包括:1. wait(), notify(), notifyAll()等方法介绍2. wait()和notify()3. wait(long timeout)和notify()4. wait() 和 notifyAll()5. 为什么notify(), wait()等...

    本章,会对线程等待/唤醒方法进行介绍。涉及到的内容包括:

    1. wait(), notify(), notifyAll()等方法介绍

    2. wait()和notify()

    3. wait(long timeout)和notify()

    4. wait() 和 notifyAll()

    5. 为什么notify(), wait()等函数定义在Object中,而不是Thread中

    wait(), notify(), notifyAll()等方法介绍在Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。

    Object类中关于等待/唤醒的API详细信息如下:

    notify()        -- 唤醒在此对象监视器上等待的单个线程。

    notifyAll()   -- 唤醒在此对象监视器上等待的所有线程。

    wait()                                         -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。

    wait(long timeout)                    -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。

    wait(long timeout, int nanos)  -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。

    2. wait()和notify()示例下面通过示例演示"wait()和notify()配合使用的情形"。

    // WaitTest.java的源码

    class ThreadA extends Thread{

    public ThreadA(String name) {

    super(name);

    }

    public void run() {

    synchronized (this) {

    System.out.println(Thread.currentThread().getName()+" call notify()");

    // 唤醒当前的wait线程

    notify();

    }

    }

    }

    public class WaitTest {

    public static void main(String[] args) {

    ThreadA t1 = new ThreadA("t1");

    synchronized(t1) {

    try {

    // 启动“线程t1”

    System.out.println(Thread.currentThread().getName()+" start t1");

    t1.start();

    // 主线程等待t1通过notify()唤醒。

    System.out.println(Thread.currentThread().getName()+" wait()");

    t1.wait();

    System.out.println(Thread.currentThread().getName()+" continue");

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }

    }

    运行结果:

    main start t1

    main wait()

    t1 call notify()

    main continue

    结果说明:

    如下图,说明了“主线程”和“线程t1”的流程。

    (01) 注意,图中"主线程" 代表“主线程main”。"线程t1" 代表WaitTest中启动的“线程t1”。 而“锁” 代表“t1这个对象的同步锁”。

    (02) “主线程”通过 new ThreadA("t1") 新建“线程t1”。随后通过synchronized(t1)获取“t1对象的同步锁”。然后调用t1.start()启动“线程t1”。

    (03) “主线程”执行t1.wait() 释放“t1对象的锁”并且进入“等待(阻塞)状态”。等待t1对象上的线程通过notify() 或 notifyAll()将其唤醒。

    (04) “线程t1”运行之后,通过synchronized(this)获取“当前对象的锁”;接着调用notify()唤醒“当前对象上的等待线程”,也就是唤醒“主线程”。

    (05) “线程t1”运行完毕之后,释放“当前对象的锁”。紧接着,“主线程”获取“t1对象的锁”,然后接着运行。

    90b724dd8a91f8e7baf324f1d1db3b63.png

    对于上面的代码?曾经有个朋友问到过:t1.wait()应该是让“线程t1”等待;但是,为什么却是让“主线程main”等待了呢?

    在解答该问题前,我们先看看jdk文档中关于wait的一段介绍:

    Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.

    In other words, this method behaves exactly as if it simply performs the call wait(0).

    The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

    中文意思大概是:

    引起“当前线程”等待,直到另外一个线程调用notify()或notifyAll()唤醒该线程。换句话说,这个方法和wait(0)的效果一样!(补充,对于wait(long millis)方法,当millis为0时,表示无限等待,直到被notify()或notifyAll()唤醒)。

    “当前线程”在调用wait()时,必须拥有该对象的同步锁。该线程调用wait()之后,会释放该锁;然后一直等待直到“其它线程”调用对象的同步锁的notify()或notifyAll()方法。然后,该线程继续等待直到它重新获取“该对象的同步锁”,然后就可以接着运行。

    注意:jdk的解释中,说wait()的作用是让“当前线程”等待,而“当前线程”是指正在cpu上运行的线程!

    这也意味着,虽然t1.wait()是通过“线程t1”调用的wait()方法,但是调用t1.wait()的地方是在“主线程main”中。而主线程必须是“当前线程”,也就是运行状态,才可以执行t1.wait()。所以,此时的“当前线程”是“主线程main”!因此,t1.wait()是让“主线程”等待,而不是“线程t1”!

    3. wait(long timeout)和notify()

    wait(long timeout)会让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。

    下面的示例就是演示wait(long timeout)在超时情况下,线程被唤醒的情况。

    // WaitTimeoutTest.java的源码

    class ThreadA extends Thread{

    public ThreadA(String name) {

    super(name);

    }

    public void run() {

    System.out.println(Thread.currentThread().getName() + " run ");

    // 死循环,不断运行。

    while(true)

    }

    }

    public class WaitTimeoutTest {

    public static void main(String[] args) {

    ThreadA t1 = new ThreadA("t1");

    synchronized(t1) {

    try {

    // 启动“线程t1”

    System.out.println(Thread.currentThread().getName() + " start t1");

    t1.start();

    // 主线程等待t1通过notify()唤醒 或 notifyAll()唤醒,或超过3000ms延时;然后才被唤醒。

    System.out.println(Thread.currentThread().getName() + " call wait ");

    t1.wait(3000);

    System.out.println(Thread.currentThread().getName() + " continue");

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }

    }

    运行结果:

    main start t1

    main call wait

    t1 run                  // 大约3秒之后...输出“main continue”

    main continue

    结果说明:

    如下图,说明了“主线程”和“线程t1”的流程。

    (01) 注意,图中"主线程" 代表WaitTimeoutTest主线程(即,线程main)。"线程t1" 代表WaitTest中启动的线程t1。 而“锁” 代表“t1这个对象的同步锁”。

    (02) 主线程main执行t1.start()启动“线程t1”。

    (03) 主线程main执行t1.wait(3000),此时,主线程进入“阻塞状态”。需要“用于t1对象锁的线程通过notify() 或者 notifyAll()将其唤醒” 或者 “超时3000ms之后”,主线程main才进入到“就绪状态”,然后才可以运行。

    (04) “线程t1”运行之后,进入了死循环,一直不断的运行。

    (05) 超时3000ms之后,主线程main会进入到“就绪状态”,然后接着进入“运行状态”。

    874a876125790c99e3987f768aac9ac6.png

    4. wait() 和 notifyAll()

    通过前面的示例,我们知道 notify() 可以唤醒在此对象监视器上等待的单个线程。

    下面,我们通过示例演示notifyAll()的用法;它的作用是唤醒在此对象监视器上等待的所有线程。

    public class NotifyAllTest {

    private static Object obj = new Object();

    public static void main(String[] args) {

    ThreadA t1 = new ThreadA("t1");

    ThreadA t2 = new ThreadA("t2");

    ThreadA t3 = new ThreadA("t3");

    t1.start();

    t2.start();

    t3.start();

    try {

    System.out.println(Thread.currentThread().getName()+" sleep(3000)");

    Thread.sleep(3000);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    synchronized(obj) {

    // 主线程等待唤醒。

    System.out.println(Thread.currentThread().getName()+" notifyAll()");

    obj.notifyAll();

    }

    }

    static class ThreadA extends Thread{

    public ThreadA(String name){

    super(name);

    }

    public void run() {

    synchronized (obj) {

    try {

    // 打印输出结果

    System.out.println(Thread.currentThread().getName() + " wait");

    // 唤醒当前的wait线程

    obj.wait();

    // 打印输出结果

    System.out.println(Thread.currentThread().getName() + " continue");

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }

    }

    }

    运行结果:

    t1 wait

    main sleep(3000)

    t3 wait

    t2 wait

    main notifyAll()

    t2 continue

    t3 continue

    t1 continue

    结果说明:

    参考下面的流程图。

    (01) 主线程中新建并且启动了3个线程"t1", "t2"和"t3"。

    (02) 主线程通过sleep(3000)休眠3秒。在主线程休眠3秒的过程中,我们假设"t1", "t2"和"t3"这3个线程都运行了。以"t1"为例,当它运行的时候,它会执行obj.wait()等待其它线程通过notify()或额nofityAll()来唤醒它;相同的道理,"t2"和"t3"也会等待其它线程通过nofity()或nofityAll()来唤醒它们。

    (03) 主线程休眠3秒之后,接着运行。执行 obj.notifyAll() 唤醒obj上的等待线程,即唤醒"t1", "t2"和"t3"这3个线程。 紧接着,主线程的synchronized(obj)运行完毕之后,主线程释放“obj锁”。这样,"t1", "t2"和"t3"就可以获取“obj锁”而继续运行了!

    3e64024a2383c4a8002a5fa4041e43f2.png

    5. 为什么notify(), wait()等函数定义在Object中,而不是Thread中

    Object中的wait(), notify()等函数,和synchronized一样,会对“对象的同步锁”进行操作。

    wait()会使“当前线程”等待,因为线程进入等待状态,所以线程应该释放它锁持有的“同步锁”,否则其它线程获取不到该“同步锁”而无法运行!

    OK,线程调用wait()之后,会释放它锁持有的“同步锁”;而且,根据前面的介绍,我们知道:等待线程可以被notify()或notifyAll()唤醒。现在,请思考一个问题:notify()是依据什么唤醒等待线程的?或者说,wait()等待线程和notify()之间是通过什么关联起来的?答案是:依据“对象的同步锁”。

    负责唤醒等待线程的那个线程(我们称为“唤醒线程”),它只有在获取“该对象的同步锁”(这里的同步锁必须和等待线程的同步锁是同一个),并且调用notify()或notifyAll()方法之后,才能唤醒等待线程。虽然,等待线程被唤醒;但是,它不能立刻执行,因为唤醒线程还持有“该对象的同步锁”。必须等到唤醒线程释放了“对象的同步锁”之后,等待线程才能获取到“对象的同步锁”进而继续运行。

    总之,notify(), wait()依赖于“同步锁”,而“同步锁”是对象锁持有,并且每个对象有且仅有一个!这就是为什么notify(), wait()等函数定义在Object类,而不是Thread类中的原因。

    展开全文
  • 多线程notify()是有序唤醒线程的!!有序的!!有序的!! 重要的事情说三遍 就是有序的唤醒等待的线程的 之前网上有很多说notify是随时唤醒线程的 是错的 这里我们用两个例子来举证一下 ,这种方式比源码来的简单 ...

    多线程notify()是有序唤醒线程的!!有序的!!有序的!!

    重要的事情说三遍 就是有序的唤醒等待的线程的

    之前网上有很多说notify是随时唤醒线程的 是错的
    这里我们用两个例子来举证一下 ,这种方式比源码来的简单
    当然如果不够详细的话 大家可以去研究一下 wait和notify的源码,这里我就不贴出来了

    package com.zmkj.admin.test;
    
    import java.util.LinkedList;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 研究 notify 唤醒线程的顺序  有序?随机?
     *
     * @author sunminghao
     */
    public class NotifySequence {
    
        //等待列表, 用来记录等待的顺序
        private static List<String> waitList = new LinkedList<>();
        //唤醒列表, 用来唤醒的顺序
        private static List<String> notifyList = new LinkedList<>();
    
        private static Object lock = new Object();
    
        public static void main(String[] args) throws InterruptedException {
            //创建10个线程
            for(int i=0;i<10;i++){
                String threadName = Integer.toString(i);
                new Thread(() -> {
                    synchronized (lock) {
                        String cthreadName = Thread.currentThread().getName();
                        System.out.println("线程 ["+cthreadName+"] 正在等待.");
                        waitList.add(cthreadName);
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("线程 ["+cthreadName+"] 被唤醒了.");
                        notifyList.add(cthreadName);
                    }
                },threadName).start();
    
                TimeUnit.MILLISECONDS.sleep(50);
            }
    
            TimeUnit.SECONDS.sleep(1);
    
            for(int i=0;i<10;i++){
                synchronized (lock) {
                    System.out.println("唤醒一个线程");
                    lock.notify();
                    //TODO 1
                    TimeUnit.MILLISECONDS.sleep(10);
                }
                //TODO 2
    //            System.out.println("释放一个锁");
    //            TimeUnit.MILLISECONDS.sleep(10);
            }
            TimeUnit.SECONDS.sleep(1);
    
            System.out.println("wait顺序:"+waitList.toString());
            System.out.println("唤醒顺序:"+notifyList.toString());
        }
    
    
        /**
         * 当我们 分别注释 todo 1 和 2
         * 的时间sleep的时候  我们会发现不同的效果
         * 当 1 部分代码有效的时候  是无序随机的唤醒线程
         * 当 2 部分代码有效的时候  是有序的唤醒线程
         *
         * 这就要问个为什么了,为什么呢?
         * 为什么大多说人都认为notify是随机唤醒线程的呢?
         * 这个时候你是不是在想  毕竟notify()并没有制定需要唤醒的线程啊  这么说也没问题  接下来看原因
         *
         * 一问:notify是立即释放锁的吗?
         * 首先研究一下 WaitAndNotify 类方法,上一篇文章
         * 
         * https://blog.csdn.net/qq_34129814/article/details/117222339
         *
         * 答案是  不是的
         *
         * 二问:为啥 一行代码 位置的不同 引发的结果天壤之别
         *
         * 细心的话 你会注意到我们 在外层加了一个synchronized 锁
         *
         *
         * lock.notify();去唤醒等待线程, 我们假设唤醒了线程A;
         * 但是因为后面还要执行TimeUnit.MILLISECONDS.sleep(10)所以lock锁并没有被释放!
         * 当TimeUnit.MILLISECONDS.sleep(10)执行完毕后, lock被释放,
         *
         * 此时被唤醒的线程A想获取lock,
         * 但是我们的for循环中synchronized (lock)也想继续获取lock,
         * 于是两者发生了锁竞争.
         *
         * 由于synchronized实际上不是公平锁,其锁竞争的机制具有随机性
         * 这就导致了最终, 我们看到的结果好像是随机的!
         * 当我们把TimeUnit.MILLISECONDS.sleep(10);移出synchronized同步块后
         * lock锁立即被释放了,
         * 并且紧跟的 TimeUnit.SECONDS.sleep(1)确保被唤醒的线程能够获得lock锁立刻执行,
         * 所以, 我们看到的结果才是正确的!
         *
         * 具体原因 wait 内部采用了队列 具有公平性  是按照顺序插入的
         * 而notify是顺序执行的。所以就先进先出
         *
         * 结论:  有序的!!!!
         *
         */
    }
    
    

    一问:notify是立即释放锁的吗?
    首先研究一下 WaitAndNotify 类方法,上一篇文章
    https://blog.csdn.net/qq_34129814/article/details/117222339

    二问:为啥 一行代码 位置的不同 引发的结果天壤之别 一个是有序 一个是无序?

    展开全文
  • 前几篇都介绍了几个关于Thread的几个方法,下面就来总结一下吧,首先来看一张图,下面这张图很清晰的说明了线程的状态与Thread中的各个方法之间的关系,很经典的!在Java中创建线程有两种方法:使用Thread类和使用...

    前几篇都介绍了几个关于Thread的几个方法,下面就来总结一下吧,首先来看一张图,下面这张图很清晰的说明了线程的状态与Thread中的各个方法之间的关系,很经典的!

    59227418_1.jpg

    在Java中创建线程有两种方法:使用Thread类和使用Runnable接口。

    要注意的是Thread类也实现了Runnable接口,因此,从Thread类

    线程的生命周期:

    1.新建状态(New):用new语句创建的线程对象处于新建状态,此时它和其它的java对象一样,仅仅在堆中被分配了内存 2.就绪状态(Runnable):当一个线程创建了以后,其他的线程调用了它的start()方法,该线程就进入了就绪状态。处于这个状态的 线程位于可运行池中,等待获得CPU的使用权 3.运行状态(Running): 处于这个状态的线程占用CPU,执行程序的代码 4.阻塞状态(Blocked): 当线程处于阻塞状态时,java虚拟机不会给线程分配CPU,直到线程重新进入就绪状态,它才有机会转到 运行状态。 阻塞状态分为三种情况: 1)、 位于对象等待池中的阻塞状态:当线程运行时,如果执行了某个对象的wait()方法,java虚拟机就回把线程放到这个对象的等待池中 2)、 位于对象锁中的阻塞状态,当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他的线程占用,JVM就会把这个线程放到这个对象的琐池中。

    3)、 其它的阻塞状态:当前线程执行了sleep()方法,或者调用了其它线程的join()方法,或者发出了I/O请求时,就会进入这个状态中。

    一、创建并运行线程

    当调用start方法后,线程开始执行run方法中的代码。线程进入运行状态。可以通过Thread类的isAlive方法来判断线程是否处于运行状态。当线程处于运行状态时,isAlive返回true,当isAlive返回false时,可能线程处于等待状态,也可能处于停止状态。

    二、挂起和唤醒线程

    一但线程开始执行run方法,就会一直到这个run方法执行完成这个线程才退出。但在线程执行的过程中,可以通过两个方法使线程暂时停止执行。这两个方法是suspend和sleep。在使用suspend挂起线程后,可以通过resume方法唤醒线程。而使用sleep使线程休眠后,只能在设定的时间后使线程处于就绪状态(在线程休眠结束后,线程不一定会马上执行,只是进入了就绪状态,等待着系统进行调度)。

    虽然suspend和resume可以很方便地使线程挂起和唤醒,但由于使用这两个方法可能会造成一些不可预料的事情发生,因此,这两个方法被标识为deprecated(弃用)标记,这表明在以后的jdk版本中这两个方法可能被删除,所以尽量不要使用这两个方法来操作线程。

    三、终止线程的三种方法

    有三种方法可以使终止线程。 1.  使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。 2.  使用stop方法强行终止线程(线程中调用了阻塞代码)(这个方法不推荐使用,因为stop是依靠抛出异常来结束线程的,也可能发生不可预料的结果)。如果没有调用阻塞代码,可以正常结束线程。

    3.  使用interrupt方法中断线程(线程中调用了阻塞代码)(其实这种方法也是通过抛出异常来结束线程的)。如果没有调用阻塞代码,可以通过判断线程的中断标志位来介绍线程。

    线程的几个方法:

    join():等待此线程死亡后再继续,可使异步线程变为同步线程 interrupt():中断线程,被中断线程会抛InterruptedException wait():等待获取锁:表示等待获取某个锁执行了该方法的线程释放对象的锁,JVM会把该线程放到对象的等待池中。该线程等待其它线程唤醒 notify():执行该方法的线程唤醒在对象的等待池中等待的一个线程,JVM从对象的等待池中随机选择一个线程,把它转到对象的锁池中。使线程由阻塞队列进入就绪状态 sleep():让当前正在执行的线程休眠,有一个用法可以代替yield函数——sleep(0) yield():暂停当前正在执行的线程对象,并执行其他线程。也就是交出CPU一段时间(其他同样的优先级或者更高优先级的线程可以获取到运行的机会) sleep和yield区别: 1、sleep()方法会给其他线程运行的机会,而不考虑其他线程的优先级,因此会给较低线程一个运行的机会;yield()方法只会给相同优先级或者更高优先级的线程一个运行的机会。 2、当线程执行了sleep(long millis)方法后,将转到阻塞状态,参数millis指定

    4、sleep()方法比yield()方法具有更好的移植性

    如果希望明确地让一个线程给另外一个线程运行的机会,可以采取以下的办法之一: 1、调整各个线程的优先级 2、让处于运行状态的线程调用Thread.sleep()方法 3、让处于运行状态的线程调用Thread.yield()方法

    4、让处于运行状态的线程调用另一个线程的join()方法

    首先,wait()和notify(),notifyAll()是Object类的方法,sleep()和yield()是Thread类的方法。 (1).常用的wait方法有wait()和wait(long timeout): void wait()在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。 void wait(long timeout)在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。 wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其它synchronized数据可被别的线程使用。

    wait()和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronized代码块中进行调用。如果在non-    synchronized函数或non-synchronized代码块中进行调用,虽然能编译通过,但在运 行时会发生IllegalMonitorStateException的异常。

    (2).Thread.sleep(long millis),必须带有一个时间参数。 sleep(long)使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会被执行; sleep(long)可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会;

    sleep(long)是不会释放锁标志的。

    (3).yield()没有参数。

    sleep 方法使当前运行中的线程睡眼一段时间,进入不可运行状态,这段时间的长短是由程序设定的,yield 方法使当前线程让出CPU占有权,但让出的时间是不可设定的。yield()也不会释放锁标志。

    实际上,yield()方法对应了如下操作: 先检测当前是否有相同优先级的线程处于同可运行状态,如有,则把 CPU 的占有权交给此线程,否则继续运行原来的线程。所以yield()方法称为“退让”,它把运行机会让给了同等优先级的其他线程。

    sleep方法允许较低优先级的线程获得运行机会,但yield()方法执行时,当前线程仍处在可运行状态,所以不可能让出较低优先级的线程些时获得CPU占有权。 在一个运行系统中,如果较高优先级的线程没有调用 sleep 方法,又没有受到 I/O阻塞,那么较低优先级线程只能等待所有较高优先级的线程运行结束,才有机会运行。

    yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。所以yield()只能使同优先级的线程有执行的机会。

    volitile 语义

    volatile相当于synchronized的弱实现,也就是说volatile实现了类似synchronized的语义,却又没有锁机制。它确保对volatile字段的更新以可预见的方式告知其他的线程。 volatile包含以下语义: (1)Java 存储

    数据同步:

    线程同步的特征: 1、如果一个同步代码块和非同步代码块同时操作共享资源,仍然会造成对共享资源的竞争。因为当一个线程执行一个对象的同步代码块时,其他的线程仍然可以执行对象的非同步代码块。(所谓的线程之间保持同步,是指不同的线程在执行同一个对象的同步代码块时,因为要获得对象的同步锁而互相牵制) 2、每个对象都有唯一的同步锁 3、在静态方法前面可以使用synchronized修饰符,但是要注意的是锁对象是类(用Object.class而不能用this),而不是这个类的对象。 4、当一个线程开始执行同步代码块时,并不意味着必须以不间断的方式运行,进入同步代码块的线程可以执行Thread.sleep()或者执行Thread.yield()方法,此时它并不释放对象锁,只是把运行的机会让给其他的线程。

    5、synchronized

    6、synchronized

    写了一天了,终于搞定了,写博客很伤人呀!

    展开全文
  • publicclassThreadPriority{publicstaticvoidmain(String[]args){Producerp=new...改变了监视的实例,所以导致当前线程不是此对象监视器的所有者。这才是真正的原因。由于做了自加操作,Integer 作了自动拆箱,...

    public class ThreadPriority {public static void main(String[] args) {Producer p = new Producer();p.start();for (int i = 1; i 

    由于slotNum++;改变了监视的实例,所以导致当前线程不是此对象监视器的所有者。这才是真正的原因。

    由于做了自加操作,Integer 作了自动拆箱,自减完成后又自动装箱了,因此在 slotNum++之后的 slotNum 与之前的 slotNum 不是同一个对象了,所以在 notifyAll 时会抛出无效的监视器状态异常。

    参考这个

    修改后的代码如下:

    package future;

    import java.util.concurrent.atomic.AtomicInteger;

    public class ThreadPriority {

    public static void main(String[] args) {

    for (int i = 1; i < 5; i++) {

    Consumer cr = new Consumer();

    cr.setPriority(i);

    cr.start();

    }

    Producer p = new Producer();

    p.start();

    }

    }

    class Consumer extends Thread {

    public Consumer()

    {

    setDaemon(true);

    }

    public void run() {

    try {

    synchronized (Producer.slotNum) {

    if (Producer.slotNum.get()== 0)

    Producer.slotNum.wait();

    Producer.slotNum.decrementAndGet();

    System.out.println(" Thread  " + this.getId() + " consumer 1!");

    }

    } catch (InterruptedException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    }

    }

    class Producer extends Thread {

    public static AtomicInteger  slotNum = new AtomicInteger(10);

    public Producer()

    {

    setDaemon(true);

    }

    // public void addSlot()

    // {

    //  slotNum ++;

    // }

    public void run() {

    synchronized (slotNum) {

    //   slotNum++;

    //   slotNum = slotNum +1 ;

    //   addSlot();

    slotNum.incrementAndGet();

    slotNum.notifyAll();

    System.out.println(" Thread " + this.getId() + " producer 1!");

    }

    }

    }

    展开全文
  • 线程获取同步状态时如果获取失败,则加入CLH同步队列,通过通过自旋的方式不断获取同步状态,但是在自旋的过程中则需要判断当前线程是否需要阻塞,其主要方法在acquireQueued():if (shouldParkAfterFailedAcquire...
  • 1、线程常见用法: // thread example #include <iostream> // std::cout #include <thread> // std::thread void foo() { // do stuff... } void bar(int x) { // do stuff... } int main() { std:...
  • classss{publicstaticinti1=0;publicstaticinti2=0;privateObjecttask=newObject();}classnumberextendsThread{intm=500;publicstaticnumberx1;//privatestaticObjecttask=newObject(...class ss{public static int ...
  • } } 这个类里的方法我准备让另外两个类来调用并继承runnable,然后我发现一直都是卡在move方法这里,我觉得是没有成功唤醒move方法所在类的线程的原因,可我调用了notify()方法,用了notifyAll也是这样,请问是为...
  • Condition 可以指定唤醒线程? 先说说问题的起源,最近在网上看到一个网友提问,说是看到了一个教学视频,讲到了线程的执行顺序问题,有一个疑惑,先将代码贴出来。 /** * @describe: 测试 * @author: sunlight *...
  • 小编典典futex的和当前实现并行线程的Linux之前,NPTL(需要内核2.6和更高版本),此外,还有两个线程库与POSIX线程API的Linux:Linux线程这和NGPT(基于对牛羚第P。LinuxThreads中是唯一的广泛应用libpthread已有多年...
  • notifyAll唤醒线程顺序

    2021-03-23 23:16:48
    notifyAll()方法按照后进先出算法唤醒所有wait状态的线程,即LIFO。 执行完唤醒方法,并不会立即唤醒等待线程,在hotspot中是退出同步块的时候才会去真正唤醒对应的线程。 notifyAll()唤醒过程还使用了monitorexit...
  • Linux线程唤醒与等待

    2021-05-14 02:40:01
    生产者消费者模式在程序设计中出现频率非常高,经常会有线程间通过消息队列或其他共享变量进行交互的场景。而这时就会出现一个问题,消费者如何知道生产者已经生产了数据呢?有的程序会采取消费者循环判断消息队列...
  • 这是一个奇怪的疑难问题初始化扫描电镜和第一destory它,然后我在thread.then再初始化它,我不能唤醒它again.the代码:posix sem_post无法唤醒线程中sem init所在的sem_wait。 Linux的#include #include #include #...
  • 如果线程是因为调用了wait()、sleep()或者join()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException来唤醒它;如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接接触...
  • Let's say I want to create an object that basically runs a thread infinitely. I want the thread to sleep while there is no need for him, but when there is a need for certain job to be done, it wakes t...
  • LockSupport工具类定义了一组公共的静态方法,提供了最基本的线程阻塞和唤醒功能,是创建锁和其他同步类的基础,你会发现,AQS中阻塞线程和唤醒线程的地方,就是使用LockSupport提供的park和unpark方法,比如下面这...
  • 线程通信个人理解为当一个线程A执行到某个特定条件时,通知其他线程继续执行
  • notify()方法唤醒处于等待的线程 谁先等待...MyThreadB.clsss 唤醒线程类 Test.class 测试线程类 MyService.class public class MyService { private Object lock = new Object(); public void waitMethod() { try
  • 等待其他线程调用unpark()方法唤醒自己。那么当我们调用interrupt()方法时,是否可以中断被操作系统挂起的线程呢?public class ParkDemo {public static void main(String[] args) {Thread t1 = new Th...
  • 熟悉线程操作的小伙伴应该知道,Java中线程的挂起和唤醒一般用synchronized + wait + notify完成。比如:synchronized(o) {o.wait(); //wait状态}在其他线程中o.notify(),就可以唤醒在o上wait的线程。可是如果o上有...
  • 我有一个活动多数民众赞成... 这就是我的代码:如何在Android中唤醒一个线程睡眠private final int delay = 3000;public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setConte...
  • } // 唤醒线程 private void unparkSuccessor(Node node) { //... if (s != null) LockSupport.unpark(s.thread); } park与unpark相关方法 LockSupport提供了一组park开头的方法来阻塞当前线程【省略static】: ...
  • 群里有学C#转Java的小朋友问:Java中有木有一个办法唤醒一个“指定的”线程。熟悉线程操作的小朋友应该知道,Java中线程的挂起和唤醒一般用synchronized + wait + notify完成。比如:synchronized(o) {o.wait(); //...
  • 一个程序问题之前写过这样一个C程序:...在同步调用情况下,接口调用后调用者被阻塞,等待工作线程处理完成后,将调用者唤醒。伪代码如下:[调用接口]add_command(cmd, pid); /* 1 */raise(SIGSTOP); /* 2 */get_re...
  • 我们都知道,Android的Handler机制,会在线程中开启消息循环,不断的从消息队列中取出消息,这个机制保证了主线程能够及时的接收和处理消息。 通常在消息队列中(MessageQueue)中没有消息的时候,会调用MessageQueue...
  • 线程唤醒的两种方式

    2021-02-22 14:33:40
    阻塞的线程,可以通过下面两种方式唤醒: 通过 LockSupport.unpark(thread) 唤醒 使用中断 thread.interrupt() 唤醒 public static void main(String[] args) { Thread t0 = new Thread(() -> { Thread ...
  • 熟悉线程操作的小伙伴应该知道,Java中线程的挂起和唤醒一般用synchronized + wait + notify完成。 比如: synchronized(o) { o.wait(); //wait状态 } 在其他线程中o.notify(),就可以唤醒在o上wait的线程。 ...
  • notity:唤醒随机一个当前对象等待的线程,并不会释放锁notityAll:唤醒所有当前对象等待的线程,并不会释放锁遇到问题:代码如下:package com.zhen.ten_chapter.question;/*** @author zhen* @Date 2019/4/18 10:...
  • 账号提钱、存钱实例方法public class ...private int maxbalance;public account(int balance){this.balance=balance;}//同步方法 取钱public synchronized void transferout(int money) {//线程同步//synchro...
  • 注意:java中的notifyAll和notify都是唤醒线程的操作,notify只会唤醒等待池中的某一个线程,但是不确定是哪一个线程,notifyAll是针对指定对象里面的所有线程执行唤醒操作,指定对象一旦唤醒成功。则会立即加入线程...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 226,189
精华内容 90,475
关键字:

唤醒线程