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 "谢谢-- 转换符:% ...
随机推荐
- Cocos2d-x中使用OpenGL ES2.0编写shader
这几天在看子龙山人的关于OpenGL的文章,先依葫芦画瓢,能看到些东西,才能慢慢深入了解,当入门文章不错,但是其中遇到的一些问题,折腾了一些时间,为了方便和我一样的小白们,在这篇文章中进行写补充. O ...
- sql 随机函数newid()
newid()返回的是uniqueidentifier类型的唯一值.newid()每次产生的值都不一样 从表中随机获取前N条记录 select top N * from table_name ord ...
- [wikioi2926][AHOI2002]黑白瓷砖(Polya定理)
小可可在课余的时候受美术老师的委派从事一项漆绘瓷砖的任务.首先把n(n+1)/2块正六边形瓷砖拼成三角形的形状,右图给出了n=3时拼成的“瓷砖三角形”.然后把每一块瓷砖漆成纯白色或者纯黑色,而且每块瓷 ...
- [工具类]文件或文件夹xx已存在,则重命名为xx(n)
写在前面 最近在弄一个文件传输的一个东东,在接收文件的时候,如果文件已经存在,该如何处理?提示?删除?感觉直接删除实在不太合适,万一这个文件对用户来说很重要,你给他删除了肯定不行.然后就想到了,win ...
- Moqui学习之数据与资源
资源位置: 资源门面位置的字符串类似于URL的构成方式:协议,主机,可选端口和文件名.它支持标准的java URL协议(http https ftp jar file).同样也支持一些扩展的协议: c ...
- loaded the "XXXView" nib but the view outlet was not set 解决方案
'-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "XXXView" nib but the view o ...
- js实现开灯关灯效果
<!DOCTYPE html> <html> <body> <script> function changeImage() { element=docu ...
- 曲线行驶s弯道技巧图解【转】
s弯道怎么走?在走S弯的时候,最主要的就是控制车的速度,在做每个动作的时候要保持一样的速度,不要一会快一会慢的,在开的时候,因为每个人的身高,体型不一样,每个人看的点位都是不一样的,每次在开的时候要找 ...
- github 建立博客
Last login: Wed Jan 27 20:33:21 on console liukun-MBP:~ kamil$ cd ~/.ssh/ liukun-MBP:.ssh kamil$ ls ...
- list 和 str
list 和 str 两种类型数据,有不少相似的地方,也有很大的区别.本讲对她们做个简要比较,同时也是对前面有关两者的知识复习一下,所谓“温故而知新”. 相同点 都属于序列类型的数据 所谓序列类型的数 ...