zoukankan      html  css  js  c++  java
  • java笔记超级类Object多线程的应用+哲学家进餐算法内部类与多线程结合

    关于Object类中的线程方法:

    Object类是所有Java类的 父类,在该类中定义了三个与线程操作有关的方法,使得所有的Java类在创建之后就支持多线程

    这三个方法是:notify(),notifyAll(),wait(),这几个方法都是用来控制线程的运行状态的。

    方法列表如下
    notify() : 唤醒在此对象监视器上等待的单个线程
    notifyAll() : 唤醒在此对象监视器上等待的所有线程
    wait() : 在其他线程时调用此对象的notify()或者notifyAll()方法前,导致当前线程等待
    wait(long timeout) : 在notify()或者notifyAll()方法被调用之前或者超过指定的时间之前,导致当前线程等待
    wait(long timeout,int nanos) : 在notify()或者notifyAll()方法被调用之前或者超过指定的时间之前,
                                    或者其他线程中断当前线程之前,导致当前线程等待。
    --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3907610.html "谢谢--                                
    代码实例:

    package com.xhj.thread;
    
    import java.util.Random;
    
    /**
     * Object类中与线程相关方法的应用
     * 
     * @author XIEHEJUN
     * 
     */
    public class ObjectThreadMethod {
        /**
         * 定义商品最高件数
         */
        private int count = 10;
        /**
         * 生产时记录仓库商品件数
         */
        private int sum = 0;
    
        private class Producter implements Runnable {
            @Override
            public void run() {
                for (int i = 0; i < count; i++) {
                    int num = new Random().nextInt(255);
                    synchronized (this) {
                        if (sum == count) {
                            System.out.println("仓库已满");
                            try {
                                this.wait(1000);
                            } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        } else {
                            System.out.println("生产商品" + num + "号");
                            this.notify();
                            sum++;
                            System.out.println("仓库还有商品" + sum + "件");
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        }
                    }
                }
    
            }
    
        }
    
        private class Consomer implements Runnable {
            @Override
            public void run() {
                for (int i = 0; i < count; i++) {
                    synchronized (this) {
                        if (sum == 0) {
                            System.out.println("仓库已经为空,请补货");
                            try {
                                this.wait(1000);
                            } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        } else {
                            System.out.println("消费着买去了一件商品");
                            this.notify();
                            sum--;
                            System.out.println("仓库还有商品" + sum + "件");
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
    
                        }
                    }
                }
    
            }
    
        }
    
        /**
         * 调用线程服务
         */
        public void service() {
    
            Producter productor = new Producter();
            Consomer consomer = new Consomer();
            Thread thread1 = new Thread(productor);
            Thread thread2 = new Thread(consomer);
            thread1.start();
            thread2.start();
    
        }
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            ObjectThreadMethod ob = new ObjectThreadMethod();
            ob.service();
        }
    
    }

    注意:  在Object类中,以上所有的方法都是final的,切记勿与Thread类混淆
            且这几个方法要与Synchronized关键字一起使用,他们都是与对象监视器有关的,
            当前线程必须拥有此对象的监视器,否则会出现IllegalMonitorStateException异常

    下面将结合一个经典的算法实例来加深我们对于Object中多线程的方法的理解。

    经典实例--哲学家进餐问题

    有5个哲学家,每个哲学家的右手边有一根筷子,每个哲学家有两种状态,即思考和吃饭。

    当哲学家想要吃饭时,必须要保证左右手的筷子都可用,否则哲学家进入等待状态。倘若

    5个哲学家都想要吃饭,都处于等待状态,那么此时,线程发生死锁。倘若5个哲学家都不饿,

    都在认真思考,那么此时线程进入活锁(即此时都在执行思考的线程,而吃饭的线程则只能等待有人来吃饭)

    关系图:

    _thumb3_thumb

    从上图我们可以知道,根据问题描述及关系图,我们首先要建立两个关系类:筷子类--chopsticks哲学家类—Philosopher

    为了能更好的将学过的知识融汇贯通并加以运用,在这里我将用内部类的形式完成这两个类之间的联系和调用

    通过上面的关系图,我们知道筷子的可用与否,关系着哲学家所处的状态,以及将要执行的进程,因此,筷子的Available要设计成同步的

    另外对于哲学家来说,思考和吃饭是不能同时进行的,两者只能选其一,或者两者皆无法选,只能进入等待,

    因此,这两个方法thinking()和eatting()也必须是同步的

    下面是详细的代码实例:

    package com.xhj.thread;
    
    import java.util.Random;
    
    /**
     * 哲学家进餐算法(内部类和Object多线程的应用)
     * 
     * @author XIEHEJUN
     * 
     */
    public class ChopsiticksAndPhilosophers {
    
        /**
         * 筷子实体类
         * 
         */
        private class Chopstick {
            /**
             * 筷子编号
             */
            private int id;
            /**
             * 筷子是否可用,默认为可用
             */
            private volatile boolean available = true;
    
            public Chopstick(int id) {
                this.id = id;
            }
    
            public int getId() {
                return id;
            }
    
            public void setAvailable(boolean available) {
                this.available = available;
            }
    
            @Override
            public String toString() {
                // TODO Auto-generated method stub
                return id + "号筷子";
            }
    
        }
    
        /**
         * 哲学家类
         */
        private class Philosopyers implements Runnable {
            /**
             * 哲学家编号
             */
            private int id;
            /**
             * 筷子对象数组
             */
            private Chopstick[] chopsticks;
            /**
             * 哲学家状态--true表示正在思考;false表示吃饭或者等待吃饭
             */
            private volatile boolean state;
    
            /**
             * 获取哲学家左手边的筷子编号
             * 
             * @return
             */
            private Chopstick getLeftId() {
                return chopsticks[id];
            }
    
            /**
             * 获取哲学家右手边的筷子编号
             * 
             * @return
             */
            private Chopstick getRightId() {
                if (id == 0) {
                    return chopsticks[chopsticks.length - 1];
                } else {
                    return chopsticks[id - 1];
                }
            }
    
            public Philosopyers(int id, Chopstick[] chopsticks) {
                this.id = id;
                this.chopsticks = chopsticks;
            }
    
            @Override
            public String toString() {
                // TODO Auto-generated method stub
                return id + "号哲学家";
            }
    
            /**
             * 哲学家正在思考
             */
            public synchronized void thinking() {
                if (state) {
                    getLeftId().setAvailable(true);
                    getRightId().setAvailable(true);
                    System.out.println(id + "号哲学家正在思考");
                    try {
                        // 思考1秒的时间
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                state = false;
            }
    
            /**
             * 哲学家在吃饭
             */
            public synchronized void eating() {
                if (!state) {
                    if (getLeftId().available) {
                        if (getRightId().available) {
                            getLeftId().available = false;
                            getRightId().available = false;
                            System.out.println(id + "号哲学家在吃饭");
                            try {
                                // 吃饭吃一秒的时间
                                Thread.sleep(1000);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        } else {
                            System.out.println("左边" + getRightId().getId()
                                    + "号筷子不可用 " + id + "号专家进入等待状态");
                            try {
                                wait(new Random().nextInt(100));
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    } else {
                        System.out.println("右边" + getLeftId().getId() + "号筷子不可用 "
                                + id + "号专家进入等待状态");
                        try {
                            wait(new Random().nextInt(100));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                state = true;
            }
    
            @Override
            public void run() {
                // 执行2次哲学家进餐以便更好的观察其过程(可根据需要修改)
                for (int i = 0; i < 2; i++) {
                    System.out.print(i + "\t");
                    thinking();
                    eating();
                }
            }
        }
    
        /**
         * 哲学家进餐启动服务线程方法
         */
        public void service() {
            Chopstick[] chopsticks = new Chopstick[5];
            // 定义筷子数组
            for (int id = 0; id < 5; id++) {
                chopsticks[id] = new Chopstick(id);
            }
            // 5个哲学家,启动5个同步线程
            for (int id = 0; id < 5; id++) {
                Philosopyers phers = new Philosopyers(id, chopsticks);
                new Thread(phers).start();
            }
        }
    
        public static void main(String[] args) {
            ChopsiticksAndPhilosophers cap = new ChopsiticksAndPhilosophers();
            cap.service();
        }
    
    }

    运行结果:

    结果

    当我们看到这个结果时一定很惊讶,我们应该记得我们仅仅是设定了程序执行两次进餐行为,但是,这里却有三轮“进餐结果”,这又是为什么呢?

    其实主要是因为那五位哲学家在第一轮的进餐中,都很累了,所以当要开始第二轮进餐的时候,他们集体跑去吃精神粮食了---思考,使得整个程序进入活锁状态,

    即思考的进程一直在执行当中,而吃饭的进程虽然也在运行状态,但是却一直等待有人来吃饭,直到某一位哲学家实在饿得不行从思考中醒来之后,

    才真正意义上开始了第二次进餐的行为。

    知识重在总结和梳理,只有不断地去学习并运用,才能化为自己的东西。由于本人进阶猿类时间尚短,故此博客即是我学习,工作的笔记,也是和大家交流,相互提升技术的平台~希望大家不吝赐教~~ --但管努力,莫问前程,事在人为,功不唐捐。--和佑博客园
  • 相关阅读:
    Android:异步处理之Handler、Looper、MessageQueue之间的恩怨(三)
    Android:异步处理之AsyncTask的应用(二)
    Android:异步处理之Handler+Thread的应用(一)
    Android:剖析源码,随心所欲控制Toast显示
    Android:谈一谈安卓应用中的Toast情节(基础)
    Android:一个高效的UI才是一个拉风的UI(二)
    Android:一个高效的UI才是一个拉风的UI(一)
    Intent的那些事儿
    解析BroadcastReceiver之你需要了解的一些东东
    解析Service之你需要了解的一些东东
  • 原文地址:https://www.cnblogs.com/XHJT/p/3907610.html
Copyright © 2011-2022 走看看