Thread 和 Object 类中的重要方法详解


方法概览

方法概览

wait、notify、notifyAll


作用、用法:阻塞阶段、唤醒阶段、遇到中断,wait 能释放锁

  • 直到以下四种情况之一发生时,才会被唤醒
    • 另一个线程调用这个对象的 notify() 方法且刚好被唤醒的是本线程
    • 另一个线程调用这个对象的 notifyAll() 方法
    • 过了 wait(long timeout) 规定的超时时间,如果传入 0 就是永久等待;
    • 线程自身调用了 interrupt()

代码演示:展示 wait 和 notify 的基本用法

  • 研究代码执行顺序
  • 证明 wait 释放锁
public class Wait {

    public static Object object = new Object();

    static class Thread1 extends Thread {

        @Override
        public void run() {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + "开始执行了");
                try {
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程" + Thread.currentThread().getName() + "获取到了锁。");
            }
        }
    }

    static class Thread2 extends Thread {
        @Override
        public void run() {
            synchronized (object) {
                object.notify();
                System.out.println("线程" + Thread.currentThread().getName() + "调用了notify()");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread1 thread1 = new Thread1();
        Thread2 thread2 = new Thread2();
        thread1.start();
        Thread.sleep(200);
        thread2.start();
    }
}

代码演示:3个线程,线程 1 和线程 2 首先被阻塞,线程 3 唤醒它们。notify、notifyAll、start 先执行不代表线程先启动。

public class WaitNotifyAll implements Runnable {

    private static final Object resourceA = new Object();

    public static void main(String[] args) throws InterruptedException {
        Runnable r = new WaitNotifyAll();
        Thread threadA = new Thread(r);
        Thread threadB = new Thread(r);
        Thread threadC = new Thread(() -> {
            synchronized (resourceA) {
//                resourceA.notifyAll();
                resourceA.notify();
                System.out.println("ThreadC notified.");
            }
        });
        threadA.start();
        threadB.start();
        Thread.sleep(200);
        threadC.start();
    }
    
    @Override
    public void run() {
        synchronized (resourceA) {
            System.out.println(Thread.currentThread().getName()+" got resourceA lock.");
            try {
                System.out.println(Thread.currentThread().getName()+" waits to start.");
                resourceA.wait();
                System.out.println(Thread.currentThread().getName()+"'s waiting to end.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

代码演示:证明 wait 能释放锁,且只释放当前的那把锁

public class WaitNotifyReleaseOwnMonitor {

    private static volatile Object resourceA = new Object();
    private static volatile Object resourceB = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (resourceA) {
                System.out.println("ThreadA got resourceA lock.");
                synchronized (resourceB) {
                    System.out.println("ThreadA got resourceB lock.");
                    try {
                        System.out.println("ThreadA releases resourceA lock.");
                        resourceA.wait();

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (resourceA) {
                System.out.println("ThreadB got resourceA lock.");
                System.out.println("ThreadB tries to resourceB lock.");

                synchronized (resourceB) {
                    System.out.println("ThreadB got resourceB lock.");
                }
            }
        });
        thread1.start();
        thread2.start();
    }
}

原理

  1. 必须拥有 monitor 锁
  2. notify 只能唤醒一个
  3. 属于 Object 类
  4. 类似功能的 Condition
  5. 同时持有多个锁的情况

sleep


  • 作用:只想让线程在预期的时间执行,其他时候不要占用 CPU 资源
  • 不释放锁,包括 synchronized 和 lock 锁,和 wait 不同

代码演示:展示线程 sleep 的时候不释放 synchronized 的 monitor,等 sleep 时间到了以后,正常结束后才释放锁

public class SleepDontReleaseMonitor implements Runnable {

    public static void main(String[] args) {
        SleepDontReleaseMonitor sleepDontReleaseMonitor = new SleepDontReleaseMonitor();
        new Thread(sleepDontReleaseMonitor).start();
        new Thread(sleepDontReleaseMonitor).start();
    }

    @Override
    public void run() {
        syn();
    }

    private synchronized void syn() {
        System.out.println("线程" + Thread.currentThread().getName() + "获取到了monitor。");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程" + Thread.currentThread().getName() + "退出了同步代码块");
    }
}

sleep 方法的特点:sleep 方法可以让线程进入 Waiting 状态,并且不占用 CPU 资源,但是不释放锁,直到规定时间后再执行,休眠期间如果被中断,会抛出异常并清除中断状态。

sleep更优雅的实现方案:TimeUnit.SECONDS.sleep()

join


作用:因为新的线程加入了我们,所以我们要等他执行完再出发

用法主线程等待加入的子线程,注意谁等谁

封装的工具类:CountDownLatch 或 CyclicBarrier 类

join 期间主线程处于什么状态:WAITING 状态

代码演示:演示 join,注意语句输出顺序,会变化。

public class Join {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "执行完毕");
        });
        Thread thread2 = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "执行完毕");
        });

        thread.start();
        thread2.start();
        System.out.println("开始等待子线程运行完毕");
        thread.join();
        thread2.join();
        System.out.println("所有子线程执行完毕");
    }
}

yield


作用:释放我的 CPU 时间片;让当前处于运行状态的线程退回到可运行状态,让出抢占资源的机会

定位:JVM 不保证遵循,和 join 相反,join 是别人插队进来了,yield 是线程让出位置。

yield 和 sleep 区别:是否随时可能再次被调度

Thread.currentThread()


作用:当前线程,可打印出当前线程的线程名字、ID等等

start、run


前面文章有介绍过了!

stop、suspend、resume


这些方法已经弃用!


笔记来源:慕课网悟空老师视频《Java并发核心知识体系精讲》

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发飙的蜗牛咻咻咻~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值