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 "谢谢-- 转换符:% ...
随机推荐
- Mininet的安装与卸载
1.Mininet的卸载比较简单,只需要执行以下命令: sudo rm -rf /usr/local/bin/mn /usr/local/bin/mnexec /usr/local/lib/pytho ...
- IE firefox 兼容性整理
1.尽量用jquery操作. 2.jquery取值时要用准确的方法,attr(), val(), text(), html(). 例如: <span value="a"> ...
- EF实体框架之CodeFirst四
在EF实体框架之CodeFirst二中也提到数据库里面一般包括表.列.约束.主外键.级联操作.实体关系(E-R图).存储过程.视图.锁.事务.数据库结构更新等.前面几篇博客把表.存储过程.视图这些算是 ...
- Git.Framework 框架随手记--ORM新增操作
本篇主要记录具体如何新增数据,废话不多说,开始进入正文. 一. 生成工程结构 上一篇已经说到了如何生成工程结构,这里在累述一次. 1. 新建项目总体结构 使用VS新建项目结构,分层结构可以随意.我们使 ...
- bootstrap tooltip 显示提示信息
参照网上文档,是这样说的, <a data-toggle="tooltip" data-placement="top" title="这是要提示 ...
- AngularJS开发指南3:Angular主要组成部分以及如何协同工作
AngularJS的主要组成部分是: 启动(startup) - 展示“hello world!” 执行期(runtime) - AngularJS 执行期概览 作用域(scope) - 视图和控制器 ...
- 【RSYSLOG】rsyslog作为日志采集器安装配置说明
RSYSLOG is the rocket-fast system for log processing. About 由于环境基于CentOS 6.7 x64,rsyslog本身就是OS的组件,由于 ...
- 小菜鸟学 MQ(三)
创建程序测试MQ 1,创建生产者 package com.robert; import java.util.Hashtable; import java.util.Map; import javax. ...
- Java-transient
transient的作用及使用方法 都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这 ...
- 未完结第八节 JBPM流程节点
1.12个节点介绍 2.Node节点