博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
线程基础2
阅读量:7032 次
发布时间:2019-06-28

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

 

1、wait和notify

注意下面的几点:

wait和notify是Object类的常用的方法

wait要释放锁对象

notify不释放锁对象

 

 

下面实现这样一个功能:

开启两个线程一个线程向一个list集合中添加元素

另外一个线程如果监听到第一个线程添加元素的编号是5,就退出该线程

如何实现了,我们来看下面的代码

package com.bjsxt.base.conn008;import java.util.ArrayList;import java.util.List;public class ListAdd1 {    private volatile static List list = new ArrayList();            public void add(){        list.add("bjsxt");    }    public int size(){        return list.size();    }        public static void main(String[] args) {                final ListAdd1 list1 = new ListAdd1();                Thread t1 = new Thread(new Runnable() {            @Override            public void run() {                try {                    for(int i = 0; i <10; i++){                        list1.add();                        System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");                        Thread.sleep(500);                    }                    } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }, "t1");                Thread t2 = new Thread(new Runnable() {            @Override            public void run() {                while(true){                    if(list1.size() == 5){                        System.out.println("当前线程收到通知:" + Thread.currentThread().getName() + " list size = 5 线程停止..");                        throw new RuntimeException();                    }                }            }        }, "t2");                        t1.start();        t2.start();    }        }

 

程序的运行效果是:

当前线程:t1添加了一个元素..

当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程收到通知:t2 list size = 5 线程停止..
Exception in thread "t2" java.lang.RuntimeException
at com.bjsxt.base.conn008.ListAdd1$2.run(ListAdd1.java:42)
at java.lang.Thread.run(Thread.java:744)
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..

有两个点需要注意的地方:

1、第一两个线程都操作了list这个集合,为了保证集合在线程的可见性,所以用volatile申明

2、第二个线程一直开启一个while循环一直在执行判断,当等于5的时候抛出一个运行时的异常退出当前线程

这个办法效率不高一直开启一个线程一直在while循环

应该使用线程之间的通信使用wait和notify

我们来看下面的代码:

package com.bjsxt.base.conn008;import java.util.ArrayList;import java.util.List;import java.util.concurrent.CountDownLatch;/** * @author alienware * */public class ListAdd2 {    private volatile static List list = new ArrayList();            public void add(){        list.add("bjsxt");    }    public int size(){        return list.size();    }        public static void main(String[] args) {                final ListAdd2 list2 = new ListAdd2();        final Object lock = new Object();        Thread t1 = new Thread(new Runnable() {            @Override            public void run() {                try {                    synchronized (lock) {                        System.out.println("t1启动..");                        for(int i = 0; i <10; i++){                            list2.add();                            System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");                            Thread.sleep(500);                            if(list2.size() == 5){                                System.out.println("已经发出通知..");                                lock.notify();                            }                        }                                            }                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }, "t1");                Thread t2 = new Thread(new Runnable() {            @Override            public void run() {                synchronized (lock) {                    System.out.println("t2启动..");                    if(list2.size() != 5){                        try {                            lock.wait();                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                    }                    System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止..");                    throw new RuntimeException();                }            }        }, "t2");            t2.start();        t1.start();            }    }

 

程序的运行结果是:

t2启动..

t1启动..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
已经发出通知..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t2收到通知线程停止..
Exception in thread "t2" java.lang.RuntimeException
at com.bjsxt.base.conn008.ListAdd2$2.run(ListAdd2.java:60)
at java.lang.Thread.run(Thread.java:744)

没有达到我们的效果我们来分析下

t2线程先启动,首先获得锁,然后判断当前的编号不是5,执行wait操作,wait操作会将当前的线程阻塞,但是会释放锁,此时t2线程就被阻塞了,但是锁被释放了

t1线程此时就可以获得锁对象,执行代码一直执行,执行到编号是5的时候调用notify函数,notify会发出通知,不会阻塞当前的线程,但是不会释放当前的锁,这样t1线程就无法获得锁对象执行wait阻塞线程后面的代码

执行t1线程添加完成所有的代码之后,线程结束才释放锁,t2线程才能继续执行阻塞后面的代码

如何修改了,当编号是5的时候 t1线程执行notify之后应该释放锁 阻塞t1线程,然后t2线程获得锁对象,执行完成之后释放锁,让t1线程继续执行后续的代码,修改如下

package com.bjsxt.base.conn008;import java.util.ArrayList;import java.util.List;import java.util.concurrent.CountDownLatch;/** * @author alienware * */public class ListAdd2 {    private volatile static List list = new ArrayList();            public void add(){        list.add("bjsxt");    }    public int size(){        return list.size();    }        public static void main(String[] args) {                final ListAdd2 list2 = new ListAdd2();        final Object lock = new Object();        Thread t1 = new Thread(new Runnable() {            @Override            public void run() {                try {                    synchronized (lock) {                        System.out.println("t1启动..");                        for(int i = 0; i <10; i++){                            list2.add();                            System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");                            Thread.sleep(500);                            if(list2.size() == 5){                                System.out.println("已经发出通知..");                                lock.notify();                                                                lock.wait();                            }                                                    }                                            }                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }, "t1");                Thread t2 = new Thread(new Runnable() {            @Override            public void run() {                synchronized (lock) {                    System.out.println("t2启动..");                    if(list2.size() != 5){                        try {                            lock.wait();                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                    }                    System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止..");                    lock.notify();                    throw new RuntimeException();                }            }        }, "t2");            t2.start();        t1.start();            }    }

 

 

我们来看看程序运行的效果:

t2启动..

t1启动..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
已经发出通知..
Exception in thread "t2" java.lang.RuntimeException
at com.bjsxt.base.conn008.ListAdd2$2.run(ListAdd2.java:64)
at java.lang.Thread.run(Thread.java:744)
当前线程:t2收到通知线程停止..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..

就达到了我们的效果

上面的这种方式比较复杂,我们可以使用countDownlatch来解决该问题

package com.bjsxt.base.conn008;import java.util.ArrayList;import java.util.List;import java.util.concurrent.CountDownLatch;/** * @author alienware * */public class ListAdd2 {    private volatile static List list = new ArrayList();            public void add(){        list.add("bjsxt");    }    public int size(){        return list.size();    }        public static void main(String[] args) {                final ListAdd2 list2 = new ListAdd2();        /**         * CountDownLatch不需要和锁对象一起使用         *  CountDownLatch(1)的初始化值1,当值变成0的时候就会释放锁对象         * */        final CountDownLatch cLatch = new CountDownLatch(1);        Thread t1 = new Thread(new Runnable() {            @Override            public void run() {                try {                        System.out.println("t1启动..");                        for(int i = 0; i <10; i++){                            list2.add();                            System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");                            Thread.sleep(500);                            if(list2.size() == 5){                                System.out.println("已经发出通知..");                                cLatch.countDown();                            }                                                    }                                        } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }, "t1");                Thread t2 = new Thread(new Runnable() {            @Override            public void run() {                    System.out.println("t2启动..");                    if(list2.size() != 5){                        try {                            cLatch.await();                        } catch (InterruptedException e) {                            // TODO Auto-generated catch block                            e.printStackTrace();                        }                    }                    System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止..");                                        throw new RuntimeException();            }        }, "t2");            t2.start();        t1.start();            }    }

t2启动..

t1启动..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
已经发出通知..Exception in thread "t2" java.lang.RuntimeException
at com.bjsxt.base.conn008.ListAdd2$2.run(ListAdd2.java:64)
at java.lang.Thread.run(Thread.java:744)

当前线程:t1添加了一个元素..

当前线程:t2收到通知线程停止..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..

就达到了我们的效果

 

转载于:https://www.cnblogs.com/kebibuluan/p/7611904.html

你可能感兴趣的文章
linux下的DNS缓存服务
查看>>
实现一键分享的代码
查看>>
详解Linux运维工程师必备技能
查看>>
[20181109]12c sqlplus rowprefetch参数5
查看>>
bupt summer training for 16 #1 ——简单题目
查看>>
【Udacity】朴素贝叶斯
查看>>
shader 讲解的第二天 把兰伯特模型改成半兰泊特模型 函数图形绘制工具
查看>>
python3.5安装Numpy、mayploylib、opencv等额外库
查看>>
优雅绝妙的Javascript跨域问题解决方案
查看>>
Java 接口技术 Interface
查看>>
函数草稿
查看>>
织梦系统学习:文章页当前位置的写法(自认对SEO有用)
查看>>
PHP经验——PHPDoc PHP注释的标准文档(翻译自Wiki)
查看>>
vue input输入框长度限制
查看>>
深入理解Java虚拟机(类加载机制)
查看>>
在500jsp错误页面获取错误信息
查看>>
iOS-CALayer遮罩效果
查看>>
为什么需要版本管理
查看>>
五、Dart 关键字
查看>>
React Native学习笔记(一)附视频教学
查看>>