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();
        }
    
    }

    运行结果:

    结果

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

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

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

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

    知识重在总结和梳理,只有不断地去学习并运用,才能化为自己的东西。由于本人进阶猿类时间尚短,故此博客即是我学习,工作的笔记,也是和大家交流,相互提升技术的平台~希望大家不吝赐教~~ --但管努力,莫问前程,事在人为,功不唐捐。--和佑博客园
  • 相关阅读:
    Head first javascript(七)
    Python Fundamental for Django
    Head first javascript(六)
    Head first javascript(五)
    Head first javascript(四)
    Head first javascript(三)
    Head first javascript(二)
    Head first javascript(一)
    Sicily 1090. Highways 解题报告
    Python GUI programming(tkinter)
  • 原文地址:https://www.cnblogs.com/XHJT/p/3907610.html
Copyright © 2011-2022 走看看