Java多线程编程核心技术阅读笔记(线程通信)

3.1 等待/通知机制

public class WaitDemo {
    private List list = new ArrayList();

    public void add() {
        list.add("demo");
    }

    public int size() {
        System.out.println(list.size());
        return list.size();
    }


    public static class ThreadA extends Thread {
        private WaitDemo list;

        public ThreadA(WaitDemo list) {
            this.list = list;
        }

        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    list.add();
                    System.out.println("添加了" + (i + 1) + "个元素" );
                    Thread.sleep(2000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static class ThreadB extends Thread {
        private WaitDemo list;

        public ThreadB(WaitDemo list) {
            this.list = list;
        }

        @Override
        public void run() {
            try {
              while (true){
                  if(list.size() == 5){
                      System.out.println(" =5 B要退出了");
                      throw  new InterruptedException();
                  }
              }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    public static class Run{
        public static void main(String[] args) {
            WaitDemo waitDemo = new WaitDemo();
            ThreadA a = new ThreadA(waitDemo);
            a.setName("a");
            a.start();
            ThreadB b = new ThreadB(waitDemo);
            b.setName("b");
            b.start();
        }
    }

在这里插入图片描述
然两个线程间实现了通信, 但有一个弊端就是, 线程 ThreadB.java 不停地通
过 while 语句轮询机制来检测某一个条件 这样会浪费 CPU 资源如果轮洵的时间间隔很小 更浪费CPU 资源 如果轮询的时间间隔很大, 有可能会取不到想要得到的数据。 所以就需要有一种机制来实现减少 CPU 的资源浪费, 而且还可以实现在多个线程间通信它就是 “wait/notify” 机制

3.1.1 等待/通知机制的实现

方法wait的作用是使当前执行代码的线程进行等待 wait方法是Object类的方法 该方法是用来将当前线程置入预执行队列中 并且在wait所在得代码行处停止执行 直到接到通知或被中断为止 在调用wait方法之前 线程必须获得该对象级别锁 在执行wait方法之后 当前线程释放锁 在从wait返回之前 线程与其它线程竞争重新获得锁

public class Test1 {
    public static void main(String[] args) {
        try {
            String string = new String("");
            System.out.println("syn上面");
            synchronized (string){
                System.out.println("第一行");
                string.wait();
                System.out.println("wait下的代码");
            }
            System.out.println("syn 下面的代码");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

方法wait下面的代码不执行了 但线程不能永远等待下去 那样程序就停止不前 不继续向下运行了
在这里插入图片描述

package threadMain.chat3;

import threadMain.chat1.MyThread;

public class Test2 {
    public static class MyThread1 extends Thread{
        private Object lock;
        public MyThread1(Object lock){
            this.lock = lock;
        }
        @Override
        public void run() {
            try {
                synchronized (lock){
                    System.out.println("开始");
                    lock.wait();
                    System.out.println("结束");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static class MyThread2 extends Thread{
        private Object lock;
        public MyThread2(Object lock){
            this.lock = lock;
        }
        @Override
        public void run() {
                synchronized (lock){
                    System.out.println("开始");
                    lock.notify();
                    System.out.println("结束");
                }

        }
    }

    public static void main(String[] args) {
        try {
            Object lock = new Object();
            MyThread1 t1 = new MyThread1(lock);
            t1.start();
            Thread.sleep(3000);
            MyThread2 t2 = new MyThread2(lock);
            t2.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3秒后被唤醒
在这里插入图片描述

3.1.2 方法wait锁释放与notify锁不释放
public class TestMethod {
    public static class ThreadA extends Thread{
        private Object lock;
        public ThreadA(Object lock){
            this.lock = lock;
        }

        @Override
        public void run() {
            TestMethod testMethod = new TestMethod();
            testMethod.testMethod(lock);
        }
    }
    public static class ThreadB extends Thread{
        private Object lock;
        public ThreadB(Object lock){
            this.lock = lock;
        }

        @Override
        public void run() {
            TestMethod testMethod = new TestMethod();
            testMethod.testMethod(lock);
        }
    }
    public void testMethod(Object lock){
        try {
            synchronized (lock){
                System.out.println("begin wait");
                lock.wait();
                System.out.println("end wait");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Object lock = new Object();
        ThreadA a = new ThreadA(lock);
        a.start();
        ThreadB b = new ThreadB(lock);
        b.start();
    }
}

方法wait自动释放锁
在这里插入图片描述

package threadMain.chat3;

public class TestMethod {
    public static class ThreadA extends Thread{
        private Object lock;
        public ThreadA(Object lock){
            this.lock = lock;
        }

        @Override
        public void run() {
            TestMethod testMethod = new TestMethod();
            testMethod.testMethod(lock);
        }
    }
    public static class ThreadB extends Thread{
        private Object lock;
        public ThreadB(Object lock){
            this.lock = lock;
        }

        @Override
        public void run() {
            TestMethod testMethod = new TestMethod();
            testMethod.synNotifyMethod(lock);
        }
    }  public static class ThreadC extends Thread{
        private Object lock;
        public ThreadC(Object lock){
            this.lock = lock;
        }

        @Override
        public void run() {
            TestMethod testMethod = new TestMethod();
            testMethod.synNotifyMethod(lock);
        }
    }

    public void testMethod(Object lock){
        try {
            synchronized (lock){
                System.out.println("begin wait");
                lock.wait();
                System.out.println("end wait");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void synNotifyMethod(Object lock){
        try {
            synchronized (lock){
                System.out.println("begin notify");
                lock.notify();
                Thread.sleep(5000);
                System.out.println("end notify");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        Object lock = new Object();
        ThreadA a = new ThreadA(lock);
        a.start();
        ThreadB b = new ThreadB(lock);
        b.start();
        ThreadC c = new ThreadC(lock);
        c.start();
    }
}

必须执行完notify()方法所在的同步synchronized 代码块后才释放锁
在这里插入图片描述

3.1.3 当interrupt方法遇到wait方法

当线程为wait状态时 调用线程对象的interrupt方法会出现 InterruptedException异常

package threadMain.chat3;

public class TestMethod {
    public static class ThreadA extends Thread{
        private Object lock;
        public ThreadA(Object lock){
            this.lock = lock;
        }

        @Override
        public void run() {
            TestMethod testMethod = new TestMethod();
            testMethod.testMethod(lock);
        }
    }

    public void testMethod(Object lock){
        try {
            synchronized (lock){
                System.out.println("begin wait");
                lock.wait();
                System.out.println("end wait");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        try {
            Object lock = new Object();
            ThreadA a = new ThreadA(lock);
            a.start();
            Thread.sleep(5000);
            a.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述
通过上面的几个实验总结如下
执行完同步代码块就会释放对象的锁
在执行同步代码块的过程中 遇到异常而导致线程终止 锁也会被释放
在执行同步代码块的过程中 执行了锁所属对象wait方法 这个线程会释放对象锁 而此线程对象会进入线程等待池中 等待被唤醒

3.1.4 唤醒所有线程

notify 唤醒单个线程 notifyAll唤醒全部线程

3.1.5 方法wait(long)的使用

等待某一时间内是否有线程对锁进行唤醒 如果超过就自动唤醒

3.2 join的使用

很多情况 主线程创建并启动子线程 如果子线程中要进行大量的耗时运算 主线程往往早于子线程结束之前结束 如果主线程想等待子线程执行完之后结束 就要用join方法了 join方法的作用是等待线程对象销毁

public class JoinDemo extends Thread {
    @Override
    public void run() {
        try {
            int num = (int) (Math.random() * 10000);
            Thread.sleep(num);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        JoinDemo joinDemo = new JoinDemo();
        joinDemo.start();
        System.out.println("我想当joinDemo 执行完成后执行");
    }
}

joinDemo还没执行完 主线程就已经先执行完了在这里插入图片描述

3.2.1 用join来解决
public class JoinDemo extends Thread {
    @Override
    public void run() {
        try {
            int num = (int) (Math.random() * 10000);
            System.out.println(num);
            Thread.sleep(num);
            System.out.println("执行完毕");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        try {
            JoinDemo joinDemo = new JoinDemo();
            joinDemo.start();
            joinDemo.join();
            System.out.println("我想当joinDemo 执行完成后执行");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

3.2.2 方法join与异常

在join过程中 如果当线程对象被中断 则当前线程出现异常
方法 join()与 interrupt()方法如果彼此遇到, 则会出现异常

3.2.3 方法 join(long)的使用

方法 join(long)中的参数是设定等待的时间

3.2.4 方法 join(long)与sleep(long)的区别

方法 join(long)的功能在内部是使用 wait(long)方法来实现的, 所以 join(long)方法具有释放锁的特点当执行 wait(long)方法后, 当前线程的锁被释放, 那么其他线程就可以调用此线程中的同步方法了。而 Thread.sleep(long)方法却不释放锁。

3.3 类ThreadLocal的使用

类 ThreadLocal 主要解决的就是每个线程绑定自己的值, 可以将 ThreadLocal 类比喻成全局存放数据的盒子, 盒子中可以存储每个线程的私有数据。

3.3.1 方法get() 与null
public class ThreadLocalDemo {
    public static ThreadLocal t1 = new ThreadLocal();
    public static void main(String[] args) {
        if(t1.get() == null){
            System.out.println("没值");
            t1.set("我的值");
        }
        System.out.println(t1.get());
    }
}

第一次调用 tl 对象的 get()方法时返回的值是 null 通过调用set方法赋值后顺利取出值并打印到控制台上类 Threadlocal 解决的是变量在不同线程间的隔离性, 也就是不同线程拥有自己的值, 不同线程中的值是可以放人 Threadlocal 类中进行保存的

3.3.2 解决get() 返回null问题
    public static class ThreadLocalExl extends  ThreadLocal{
        @Override
        protected Object initialValue() {
            return "我是默认值 第一次get不再为null";
        }
    }

3.3.3 验证线程变量的隔离性

子线程和父线程各有各自所拥有的值

package threadMain.chat3;

import java.util.Date;

public class ThreadLocalDemo {
    public static class ThreadA extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 10; i++){
                try {
                     System.out.println("在线程中取值" + Tools.t1.get());
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static ThreadLocal t1 = new ThreadLocal();
    public static void main(String[] args) {
        try {
            for (int i = 0; i < 10; i++){
                System.out.println("在 main线程中取值" + Tools.t1.get());
                Thread.sleep(100);
            }
            Thread.sleep(5000);
            ThreadA a=  new ThreadA();
            a.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static class Tools{
        public static ThreadLocalExl t1 = new ThreadLocalExl();

    }
    public static class ThreadLocalExl extends  ThreadLocal{
        @Override
        protected Object initialValue() {
            return new Date().getTime();
        }
    }
}

在这里插入图片描述

3.4 类 InheritableThreadLocal 的使用

使用类 InheritableThreadLocal 可以在子线程中取得
父线程继承下来的值。

3.4.1 值继承

使用 InheritableThreadLocal 类可以让子线程从父线程中取得值

public class InheritableThreadLocalDemo extends InheritableThreadLocal{
    @Override
    protected Object initialValue() {
        return new Date().getTime();
    }

    public static class Tools{
        public static InheritableThreadLocalDemo t1 = new InheritableThreadLocalDemo();

    }

    public static class ThreadA extends  Thread{
        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++){
                    System.out.println("在ThreadA 线程中取值 " + Tools.t1.get());
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        try {
            for (int i =0; i < 10; i ++){
                System.out.println("在main线程取值" + Tools.t1.get());
                Thread.sleep(100);
            }
            Thread.sleep(5000);
            ThreadA a = new ThreadA();
            a.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

值成功地从父线程继承下来
在这里插入图片描述

3.4.2 值继承再修改
    @Override
    protected Object initialValue() {
        return new Date().getTime();
    }

    @Override
    protected Object childValue(Object parentValue) {
        return parentValue + "我在子线程加的";
    }

使用 InheritableThreadLocal 类需要注意一点的是, 如果子线程在取得值的同时, 主线程将 InheritableThreadLocal 中的值进行更改, 那么子线程取到的值还是旧值。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值