博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java多线程(6) - 多线程之线程通讯(二)(wait与notify案例、守护线程)
阅读量:4165 次
发布时间:2019-05-26

本文共 4334 字,大约阅读时间需要 14 分钟。

wait/notify/notifyAll案例运行过程:

      1、生产者线程,在被wait()等待后,再次被唤醒时,是继续运行下一句代码,立即生产,并没有再次判断仓库是否已有产品。

      2、无论生产者还是消费者,唤醒后,还要再次循环判断仓库是否为空,但是会引发死锁,因为所有线程都进入阻塞状态。

      3、每次唤醒的时候,唤醒所有的线程解决这个问题。

 

说明:

      1、wait() 当前线程放弃CPU执行权,并放弃锁,进入阻塞状态,直到被其他线程唤醒。

      2、notify() 唤醒持有同一锁中调用wait的线程,被唤醒的线程是进入就绪状态等待CPU执行权。

      3、notifyAll() 唤醒持有同一锁中调用wait的所有线程。

4、wait()、notify()、notifyAll() 这三个方法都是属于Object类,首先这些方法存在于同步代码方法/块中(可以理解为synchronized关键字修饰的同步方法或同步代码块中使用),而且使用这些方法时必须标识所属的同步的锁,锁可以是任意对象,所以任意对象调用的方法一定定义Object类中。

      5、wait()、notify()、notifyAll() 必须由锁对象调用。

      6、wait()、notify()、notifyAll() 要在同步函数或同步代码块中调用,否则会报错InterruptedException异常。

      7、调用wait()方法并不是立马释放锁,要等同步方法或同步代码块执行完成,同理调用notify()/notifyAll()方法会让等待锁中的线程从线程池进入等待锁池,在没有得到对象的锁之前,线程仍然无法获得CPU的调度和执行。

      8、调用wait()方法进入睡眠状态的线程会进入线程池,直到代码运行结束,这个线程也跟着结束。

/**

 * 交替运行

 */

public class J13WNThread {

    public static void main(String[] args) {

        Object object = new Object();

        new A(object).start();

        new B(object).start();

    }

}

class A extends Thread {

   

    private Object object;

   

    public A (Object object){

        this.object = object;

    }

   

    @Override

    public void run() {

        test();

    }

    public void test() {

        synchronized (object) {

             for (int i = 0; i < 100; i++) {

//               System.out.println("A - " + i);

                 if(i % 2 == 0) {

                     System.out.println("A 进入等待");

                     try {

                         object.wait();

                     } catch (InterruptedException e) {

                         e.printStackTrace();

                     }

//                   System.out.println("A 给唤醒了");

                 }else {

                     System.out.println("A 唤醒 B");

                     object.notifyAll();

                 }

             }

        }

    }

}

class B extends Thread {

   

    private Object object;

   

    public B (Object object){

        this.object = object;

    }

   

    @Override

    public void run() {

        test();

    }

    public void test() {

        synchronized (object) {

             for (int i = 0; i < 100; i++) {

//               System.out.println("B - " + i);

                 if(i % 2 == 0) {

                     System.out.println("B 唤醒 A");

                     object.notifyAll();

                    

                 }else {

                     System.out.println("B 进入等待");

                     try {

                         object.wait();

                     } catch (InterruptedException e) {

                         e.printStackTrace();

                     }

//                   System.out.println("B 给唤醒了");

                 }

             }

        }

    }

}

/**

 * wait/nofity/notifyAll模拟队列

 */

public class J10ThreadMessageQueue {

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

        Queue queue = new Queue(8);

       

        //新增

        new Thread(new Runnable() {

             @Override

             public void run() {

                 for (int i = 0; i < 20; i++) {

                     try {

                         queue.put(i);

                         Thread.sleep(1000);

                     } catch (InterruptedException e) {

                         e.printStackTrace();

                     }

                 }

             }

        }).start();

       

        Thread.sleep(10000);

       

        //取走

        new Thread(new Runnable() {

             @Override

             public void run() {

                 for (int i = 0; i < 20; i++) {

                     try {

                         queue.take();

                     } catch (InterruptedException e) {

                         e.printStackTrace();

                     }

                 }

             }

        }).start();

    }

}

class Queue {

   

    //容器

    private LinkedList linkedList = new LinkedList<Object>();

 

    //下限

    private final int MIN_SIZE = 0;

   

    //上限

    private int maxSize;

   

    //累计

    private AtomicInteger size = new AtomicInteger();

 

    //

    private Object lock = new Object();

   

    public Queue(int maxSize) {

        super();

        this.maxSize = maxSize;

    }

   

    public void put(Object object) throws InterruptedException {

        synchronized (lock) {

             //最大了,能添加要等待有人取走

             while (maxSize == size.get()) {

                 lock.wait();

             }

             //添加元素、增加步长、唤醒另外一个线程

             linkedList.add(object);

             size.incrementAndGet();

             lock.notify();

             System.out.println("新增元素:" + object);

        }

    }

 

    public Object take() throws InterruptedException {

        synchronized (lock) {

             //没有元素,等待有人加入元素

             while (MIN_SIZE == size.get()) {

                 lock.wait();

             }

             //删除元素、减少步长、唤醒另外一个线程

             Object poll = linkedList.poll();

             size.decrementAndGet();

             lock.notify();

             System.out.println("返回元素:" + poll);

        }

        return null;

    }

}

 

守护(后台)线程

      在Java中线程分为两种,用户线程守护(后台)线程,在运行线程时,默认是用户线程。

      用户线程就是之前的所有例子,即便主线程结束了,子线程还是会继续运行,直到结束。

      守护(后台)线程就是主线程结束了,守护(后台)线程也跟着结束,其中守护线程的优先级是比较低的,用于为系统中的其他对象和线程提供服务的,所以也称为服务线程。

      在代码中可以通过Thread.setDaemon(true); 设置为守护(后台)线程,默认是为false 的,即用户线程。

      垃圾回收线程就是典型的守护线程,始终以低级别的状态运行着,用于监控和管理系统中的可回收资源,当程序不再由任何运行的线程,程序就不会在产生垃圾,垃圾回收器也就无事可做了,所以当垃圾回收线程是JVM仅剩的线程时,垃圾回收线程会自动离开。

/**

 * 守护(后台)线程:在使用手机过程中,应用还是会自动下载更新包(守护线程),只要退出应用了(主线程退出),更新包也就不在下载了。

 */

public class J15DaemonThread {

    public static void main(String[] args) {

        new QQ().start();

    }

}

class QQ extends Thread {

    @Override

    public void run() {

        Download download = new Download();

        download.setDaemon(true);

        download.start();

//      download.setDaemon(true); //先设置为守护(后台)线程,再启动,否则会抛出IllegalThreadStateException异常

        for (int i = 0; i < 100; i++) {

             System.out.println("运行QQ时长:" + i);

        }

        System.out.println("退出QQ");

    }

}

class Download extends Thread {

    @Override

    public void run() {

        System.out.println("开始下载。");

        for (int i = 0; i < 100; i++) {

             System.out.println("下载 " + i + "%");

        }

        System.out.println("完成。");

    }

}

 

转载地址:http://qlmxi.baihongyu.com/

你可能感兴趣的文章
Jackson Tree Model Example
查看>>
常用js收集
查看>>
如何防止sql注入
查看>>
springmvc传值
查看>>
在Eclipse中查看Android源码
查看>>
[转]C语言printf
查看>>
对话周鸿袆:从程序员创业谈起
查看>>
Mysql中下划线问题
查看>>
Xcode 11 报错,提示libstdc++.6 缺失,解决方案
查看>>
vue项目打包后无法运行报错空白页面
查看>>
1136 . 欧拉函数
查看>>
面试题:强制类型转换
查看>>
Decorator模式
查看>>
Template模式
查看>>
Observer模式
查看>>
高性能服务器设计
查看>>
图文介绍openLDAP在windows上的安装配置
查看>>
Pentaho BI开源报表系统
查看>>
Pentaho 开发: 在eclipse中构建Pentaho BI Server工程
查看>>
JSP的内置对象及方法
查看>>