线程通讯及线程通讯方式

一、线程通讯

所谓线程通讯指的是在一个线程中的操作可以影响另一个线程

线程通讯的主要方法:wait()休眠线程 (唤醒一个线程notify)(唤醒全部线程notifyall)

wait() 使用时不和synchronized配合使用会出现监视器异常,如下:

public class Test29 {
    public static void main(String[] args) {

        Object lock = new Object();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t1.start();
    }
}
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
	at java.lang.Object.wait(Native Method)

配合使用如下:

public class Test29 {
    public static void main(String[] args) throws InterruptedException {

        Object lock = new Object();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //调用wait 方法之前必须先加锁
                    synchronized (lock) {
                        System.out.println("wait之前");
                        lock.wait();
                        System.out.println("wait之后");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t1.start();

        //注意一定要休眠一段时间,不然可能t1线程还没有进入休眠状态,主线程已经执行完了唤醒线程的操作
        Thread.sleep(500);
        System.out.println("主线程唤醒t1");

        //在主线程中唤醒线程t1
        synchronized (lock) {
            lock.notify();
            //lock.notifyAll();
        }
    }
}

wait之前
主线程唤醒t1
wait之后

这样的代码就实现了线程通讯:在主线程中通知子线程继续执行

注意事项:
1.wait方法在执行之前一定要加锁,也就是说wait在使用的时候要配合synchronized(释放锁)一起使用
2.wait和notify在配合synchronized使用时一定要使用同一把锁
3.wait和notify在配合使用时一定要操作同一把锁


  ★wait()不管是否传参,都会释放锁对象(因为synchronized会自动释放锁对象)
  ★wait()在不传递任何参数的情况下会进入waiting(无限等待)状态(不传递参数默认调用wait(0)方法)
  ★当传递一个大于0的整数时,会进入timed_waiting(超时等待状态)状态(传递0进入waiting状态,传递负数就会报错)

二、notify和notifyall唤醒线程

同样,notify和notifyall使用的时候也必须配合synchrozied一起使用,不然会报错。
notify是随机唤醒一个线程,而notifyall是唤醒所有的线程

public class Test30 {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    try {
                        System.out.println("t1 wait 之前");
                        lock.wait();
                        System.out.println("t2 wait 之后");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "t1");
        t1.start();

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    try {
                        System.out.println("t2 wait 之前");
                        lock.wait();
                        System.out.println("t2 wait 之后");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "t2");
        t2.start();

        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    try {
                        System.out.println("t3 wait 之前");
                        lock.wait();
                        System.out.println("t3 wait 之后");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "t3");
        t3.start();

        Thread.sleep(500);
        System.out.println("主线程调用唤醒方法");
        // 在主线程中唤醒线程 t1
        //这样的唤醒方式是随机的,不确定唤醒的是哪个线程
        synchronized (lock) {
            lock.notify();
//            lock.notifyAll();
        }
    }
}
t1 wait 之前
t2 wait 之前
t3 wait 之前
主线程调用唤醒方法
t2 wait 之后

Process finished with exit code -1

wait和notify/notifyall的问题:不能唤醒指定的线程

唤醒指定线程的方法:lockSupport(park()、unpark()) (如果不进行唤醒,会进入waiting状态)

import java.util.concurrent.locks.LockSupport;

public class Test31 {
    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                //让线程进行休眠
                LockSupport.park();
                System.out.println("唤醒t1");
            }
        },"t1");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                //让线程进行休眠
                LockSupport.park();
                System.out.println("唤醒t2");
            }
        },"t2");

        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                //让线程进行休眠
                LockSupport.park();
                System.out.println("唤醒t3");
            }
        },"t3");
        t1.start();
        t2.start();
        t3.start();

        //唤醒指定线程
        LockSupport.unpark(t3);
    }
}
唤醒t3


LockSupport虽然不会报Interrupt的异常,但依旧可以监听到线程终止的命令。

import java.util.concurrent.locks.LockSupport;

public class Test31 {
    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("park 之前 Interrupt 状态:" +
                        Thread.currentThread().isInterrupted());
                // 线程进入休眠
                LockSupport.park();
                System.out.println("park 之后 Interrupt 状态:" +
                        Thread.currentThread().isInterrupted());
            }
        }, "t1");
        // 启动线程
        t1.start();

        Thread.sleep(100);
        // 中止线程
        t1.interrupt();
        // 唤醒线程 t1
        LockSupport.unpark(t1);
    }
}

park 之前 Interrupt 状态:false
park 之后 Interrupt 状态:true


面试题1:wait()和sleep()区别:(面试必考)

相同点:
  1.都是让线程进入休眠状态
  2.wait()和sleep()在执行过程中都可以得到终止异常的通知
  3.wait()是用于线程之间通信的,sleep()是让线程阻塞一段时间

不同点:
  1.wait()使用必须配合synchronized使用,而sleep不需要
  2.wait()执行时会释放锁,sleep()执行不会释放锁
  3.wait()是Object的方法,而sleep()是Thread线程方法
  4.默认情况下wait(不传递任何参数或者传递的参数为0)的情况下会进入waiting状态,而sleep会进入timed_waiting状态
  5.使用wait时可以主动唤醒线程,而使用sleep时不能主动唤醒线程

面试题2:sleep(0)和wait(0)有什么区别
  1.sleep(0)表示过0毫秒之后继续执行,而wait(0)表示一直休眠
  2.sleep(0)表示重新触发一次CPU竞争,wait(0)不会触发CPU竞争

面试题3:为什么wait会释放锁,而sleep不会释放锁
  答:sleep必须要传递一个最大等待时间的,也就是说sleep是可控的(时间层面来讲),而wait是可以不传递参数的(不可控),从设计层面来讲,如果让wait这个没有超时等待时间的机制不释放锁的话,那么线程可能一直阻塞,而sleep就不存在这个问题。

面试题4:为什么sleep是Object的方法,而wait是Thread的方法?
  答:wait需要操作锁,而锁是属于对象级别的(所有的锁都是放在对象头当中的),他不是线程级别的,一个线程中可以有多把锁,为了灵活起见,所以就将wait放在Object当中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值