JAVA多线程(三)

来源:互联网 发布:淘宝沟通软件 编辑:程序博客网 时间:2024/05/16 11:04
线程同步
1、什么是线程同步
  概念上的东西在这里就不过多介绍了,线程同步,也叫做线程间通信,就是多个线程共同协作完成一件事情。

  为了完成一件事情,可能需要分很多的部分或步骤,每个部分由一个或一类线程来负责,而各个部分的处理又有先后顺序,这就对相互协作的线程有了一定的约束,也就是进程同步。

2、Java中如何实现线程同步
  在Java中,线程的同步涉及到synchronized和三个方法wait()、notify()和notifyAll()。

  synchronized在上篇中已经讲过了,这里就不再重复了。

  wait()方法与Thread类的sleep()和yield()方法类似,都是让当线程睡眠,或者说是暂停执行;与之不同的是wait()方法会释放掉当前对象的锁,也因为此wait()方法必须在synchronized块里才能被调用。

  notify()和notifyAll()方法用于唤醒之前调用wait()方法睡眠的线程,与wait()方法一样,notify()和notifyAll()也必须在synchronized块里才能被调用。

  注意wait()、notify()和notifyAll()三个方法都是Object类的,而不是Thread类的。因为这三个方法都涉及的锁的操作,而锁的操作适用于所有的对象。

3、线程同步事例
  下面的这例子,假设有一个篮子,最多可以装5个苹果,producer线程不断地往里面放苹果,consumer线程不断的吃苹果。
public class Basket{    private int numOfPlace = 5;    private int numOfApple = 0;    public synchronized void addApple() throws InterruptedException    {        while (numOfPlace <= 0)            wait();        Thread.sleep(100);        numOfPlace--;        numOfApple++;        System.out.println("Producing... [" + (numOfApple) + "] apple left.");        notify();    }    public synchronized void eatApple() throws InterruptedException    {        while (numOfApple <= 0)            wait();        numOfPlace++;        numOfApple--;        Thread.sleep(100);        System.out.println("Eating... [" + (numOfApple) + "] apple left.");        notify();    }    public static void main(String[] args) throws InterruptedException    {        Basket box = new Basket();        ExecutorService exec = Executors.newCachedThreadPool();        exec.execute(new Producer(box));        exec.execute(new Consumer(box));        TimeUnit.SECONDS.sleep(3);        exec.shutdownNow();    }}class Producer implements Runnable{    private Basket box;    public Producer(Basket box)    {        this.box = box;    }    @Override    public void run()    {        while (true)        {            try            {                box.addApple();                Thread.yield();            }            catch (InterruptedException e)            {                e.printStackTrace();                return;            }        }    }}class Consumer implements Runnable{    private Basket box;    public Consumer(Basket box)    {        this.box = box;    }    @Override    public void run()    {        while (true)        {            try            {                box.eatApple();                Thread.yield();            }            catch (InterruptedException e)            {                e.printStackTrace();                return;            }        }    }}

  Basket.addApple()方法中,首先检查篮子还有没有空间可以装入新苹果,如果没有,那么producer线程就调用Basket对象的wait()方法,等侍并释放Basket对象的锁;接着consumer线程就有机会取得Basket对象的锁并进入eatApple()方法,当consumer方法成功吃掉一个苹果后,篮子就有空间装入新的苹果了,这时eatApple()方法中调用Basket对象的notifyAll()方法通知producer线程;这时prodocer线程又会重新获得Basket对象的锁,并再次检查是否有空间装入新的苹果,成功装入一个苹果后,也会调用Basket对象的notifyAll()方法通知consumber线程。

  上面这个例子中producer和consumer线程就是通过wait()和notify()方法来通信,实现共同协作的。

4、使用Lock和Condition实现线程同步
  Java1.5提供了Lock和Condition接口,也可以实现线程同步,下面使用了Lock和Condition的方式重写了上面的例子:
public class Basket{    Lock lock = new ReentrantLock();    Condition condition = lock.newCondition();        private int numOfPlace = 5;    private int numOfApple = 0;    public void addApple() throws InterruptedException    {        try        {            lock.lock();                        while (numOfPlace <= 0)                condition.await();            Thread.sleep(100);            numOfPlace--;            numOfApple++;            System.out.println("Producing... [" + (numOfApple) + "] apple left.");            condition.signalAll();        }        finally        {            lock.unlock();        }    }    public void eatApple() throws InterruptedException    {        try        {            lock.lock();                        while (numOfApple <= 0)                condition.await();            numOfPlace++;            numOfApple--;            Thread.sleep(100);            System.out.println("Eating... [" + (numOfApple) + "] apple left.");            condition.signalAll();        }        finally        {            lock.unlock();        }            }    public static void main(String[] args) throws InterruptedException    {        Basket box = new Basket();        ExecutorService exec = Executors.newCachedThreadPool();        exec.execute(new Producer(box));        exec.execute(new Consumer(box));        TimeUnit.SECONDS.sleep(3);        exec.shutdownNow();    }}class Producer implements Runnable{    private Basket box;    public Producer(Basket box)    {        this.box = box;    }    @Override    public void run()    {        while (true)        {            try            {                box.addApple();                Thread.yield();            }            catch (InterruptedException e)            {                e.printStackTrace();                return;            }        }    }}class Consumer implements Runnable{    private Basket box;    public Consumer(Basket box)    {        this.box = box;    }    @Override    public void run()    {        while (true)        {            try            {                box.eatApple();                Thread.yield();            }            catch (InterruptedException e)            {                e.printStackTrace();                return;            }        }    }}

  新的方法提供了更好的灵活性,但也增加了出错的可能性,如果没有特殊的需求,还是采用原来的方式来得实在。
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小孩上嘴唇中间的连线碰掉了怎么办 秋田犬夏天退毛严重么 怎么办 初中数学基本没学过高中怎么办 老师家纺突然想日语文老师怎么办 微信聊天表情小企鹅不动了怎么办 微信自带小表情不全怎么办 爱奇艺电视果有图像无声音怎么办 微信表情包保存不到手机相册怎么办 才出生的兔宝宝被母兔抓伤了怎么办 老婆生气了说恨我一辈子我该怎么办 华为手机微信表情不显示含义怎么办 地下城游戏登录链接一直失败怎么办 聊天时别人打听家人不想回答怎么办 微信钱包零钱密码忘了怎么办 斗图我能怎么办我也很无奈 微信解冻设备不一致申诉失败怎么办 看不懂微信脸部表情什么意思怎么办 有的动图图片过大微信发不了怎么办 微信漂流瓶扔瓶子没有人回复怎么办 删了微信 手贱 添加 怎么办 姨妈弄到床垫上拆不下来洗怎么办 碰到情商智商都高的小人怎么办 微信聊天界面右上角的小人头怎么办 最近摸高摸到的高度越来越矮怎么办 每次孕检显示小孩子体型大怎么办? 阴阳师纸片人蓝色锦囊点掉了怎么办 抱孩子把腰闪了动不了在家怎么办 餐厅客人中有儿童服务时怎么办 脊柱胸段向右侧凸要怎么办 玩球球大作战不小心开自由了怎么办 小孩哭脸后喝水呛着了怎么办 摔跤引起的脸部半边儿僵硬怎么办 老人受了刺激大笑不止是怎么办 想让父母陪着玩 没时间怎么办 开过光的百家锁东西别人碰了怎么办 兔兔助手描述文件变了存档怎么办 扣扣没有绑手机被盗了怎么办 我的扣扣被盗了好友也被删了怎么办 小孩不胖但脖子黑怎么办呢 小孩喜欢歪头斜眼看东西怎么办 苹果x屏幕截图发送后成文字怎么办