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个哲学家都不饿,
都在认真思考,那么此时线程进入活锁(即此时都在执行思考的线程,而吃饭的线程则只能等待有人来吃饭)
关系图:
从上图我们可以知道,根据问题描述及关系图,我们首先要建立两个关系类:筷子类--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();
- }
- }
运行结果:
当我们看到这个结果时一定很惊讶,我们应该记得我们仅仅是设定了程序执行两次进餐行为,但是,这里却有三轮“进餐结果”,这又是为什么呢?
其实主要是因为那五位哲学家在第一轮的进餐中,都很累了,所以当要开始第二轮进餐的时候,他们集体跑去吃精神粮食了---思考,使得整个程序进入活锁状态,
即思考的进程一直在执行当中,而吃饭的进程虽然也在运行状态,但是却一直等待有人来吃饭,直到某一位哲学家实在饿得不行从思考中醒来之后,
才真正意义上开始了第二次进餐的行为。
java笔记--超级类Object多线程的应用+哲学家进餐算法内部类与多线程结合的更多相关文章
- Java笔记---枚举类和注解
Java笔记---枚举类和注解 一.枚举类 自定义枚举类 方式一:JDK5.0之前自定义枚举类 class Seasons { //1. 声明Seasons对象的属性 private final St ...
- Java笔记 #04# 类的初始化顺序补充
参考java中的类的初始化顺序详解 package org.sample; class Bread { Bread() { System.out.println("Bread()" ...
- Java的常用类——Object类、String类
Java的JDK中提供给我们很多封装好的类就是Java API,可以直接调用. Java 的API(API: Application(应用) Programming(程序) Interface(接口) ...
- JAVA笔记7-Object类之toString方法和equals方法
位于rt.jar\java\lang\Object.class Object类是所有Java类的根基类(Java中只有一个根基类,C++中有多个).如果在类声明中未使用extends关键字指明其基类, ...
- Java笔记--常用类
1.String类: --使用Unicode字符编码,一个字符占两个字节: --String类是一个final类,代表不可变的字符序列: --字符串是不可变的,一个字符串对象一旦被配置,其内容是不可变 ...
- JAVA笔记10__Math类、Random类、Arrays类/日期操作类/对象比较器/对象的克隆/二叉树
/** * Math类.Random类.Arrays类:具体查JAVA手册...... */ public class Main { public static void main(String[] ...
- JAVA笔记【类】
java的概述和编程基础在这里我就不过多的强调了,因为已经有学习C和C++的基础了,我在这里强调一下类和对象. [一]类的定义: Java类的定义包括类声明和类体两个部分,其中类体又包含变量声明,方法 ...
- JAVA笔记11__File类/File类作业/字节输出流、输入流/字符输出流、输入流/文件复制/转换流
/** * File类:文件的创建.删除.重命名.得到路径.创建时间等,是唯一与文件本身有关的操作类 */ public class Main { public static void main(St ...
- java笔记--String类格式化当天日期转换符文档
String类格式化当天日期 --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3877389.html "谢谢-- 转换符:% ...
随机推荐
- 由外边距合并到BFC
置顶文章:<纯CSS打造银色MacBook Air(完整版)> 上一篇:<JavaScript实现Ajax小结> 作者主页:myvin 博主QQ:851399101(点击QQ和 ...
- [wikioi2069]油画(贪心)
题目:http://www.wikioi.com/problem/2069/ 分析: 首先这个问题比较复杂,涉及到两个重要的考虑点,一个是当前拿来的颜色是否保留,一个是若保留后那么应该把当前盘子的哪个 ...
- 转:java多线程--同步容器
java同步容器 在Java的集合容器框架中,主要有四大类别:List.Set.Queue.Map.List.Set.Queue接口分别继承了Collection接口,Map本身是一个接口.注意Col ...
- sql-where
查询表时不一定每一次都要将表格内的资料都完全抓出.在许多时候,我们会需要选择性地抓资料.就我们的例子来说,我们可能只要抓出营业额超过 $1,000 的资料. 要做到这一点,需要用到 WHERE 这个指 ...
- 【SGU 104】Little shop of flowers
题意 每个花按序号顺序放到窗口,不同窗口可有不同观赏值,所有花都要放上去,求最大观赏值和花的位置. 分析 dp,dp[i][j]表示前i朵花最后一朵在j位置的最大总观赏值. dp[i][j]=max( ...
- 【前端学习】sublime开启vim模式
学习目标:在sublime下开启vim模式,了解基本vim的编辑快捷键. 下载安装Sublime Text 3 :http://www.sublimetext.com/3 Vim/Vi: Vim/Vi ...
- POJ1201 Intervals
Description You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn. Write a p ...
- Code Review Engine Learning
相关学习资料 https://www.owasp.org/index.php/Code_review https://www.owasp.org/images/8/8e/OWASP_Code_Revi ...
- sql server规范
常见的字段类型选择 1.字符类型建议采用varchar/nvarchar数据类型 2.金额货币建议采用money数据类型 3.科学计数建议采用numeric数据类型 4.自增长标识建议采用bigint ...
- ISO 基础之 (十三) protocol 协议
一 简绍 protocol,简单来说就是一系列不属于任何类的方法列表,其中声明的方法可以被任何类实现.这种模式一般称为代理(delegation)模式.通过Protocol定义各种行为,在不同的场景采 ...