关于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多线程的应用+哲学家进餐算法内部类与多线程结合的更多相关文章

  1. Java笔记---枚举类和注解

    Java笔记---枚举类和注解 一.枚举类 自定义枚举类 方式一:JDK5.0之前自定义枚举类 class Seasons { //1. 声明Seasons对象的属性 private final St ...

  2. Java笔记 #04# 类的初始化顺序补充

    参考java中的类的初始化顺序详解 package org.sample; class Bread { Bread() { System.out.println("Bread()" ...

  3. Java的常用类——Object类、String类

    Java的JDK中提供给我们很多封装好的类就是Java API,可以直接调用. Java 的API(API: Application(应用) Programming(程序) Interface(接口) ...

  4. JAVA笔记7-Object类之toString方法和equals方法

    位于rt.jar\java\lang\Object.class Object类是所有Java类的根基类(Java中只有一个根基类,C++中有多个).如果在类声明中未使用extends关键字指明其基类, ...

  5. Java笔记--常用类

    1.String类: --使用Unicode字符编码,一个字符占两个字节: --String类是一个final类,代表不可变的字符序列: --字符串是不可变的,一个字符串对象一旦被配置,其内容是不可变 ...

  6. JAVA笔记10__Math类、Random类、Arrays类/日期操作类/对象比较器/对象的克隆/二叉树

    /** * Math类.Random类.Arrays类:具体查JAVA手册...... */ public class Main { public static void main(String[] ...

  7. JAVA笔记【类】

    java的概述和编程基础在这里我就不过多的强调了,因为已经有学习C和C++的基础了,我在这里强调一下类和对象. [一]类的定义: Java类的定义包括类声明和类体两个部分,其中类体又包含变量声明,方法 ...

  8. JAVA笔记11__File类/File类作业/字节输出流、输入流/字符输出流、输入流/文件复制/转换流

    /** * File类:文件的创建.删除.重命名.得到路径.创建时间等,是唯一与文件本身有关的操作类 */ public class Main { public static void main(St ...

  9. java笔记--String类格式化当天日期转换符文档

    String类格式化当天日期 --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3877389.html "谢谢-- 转换符:% ...

随机推荐

  1. 系统安全扫描工具(appscan)的扫描类型小记

    扫描分类 不同场景需要使用不同方式的扫描类型.不能盲目的.暴力的去折腾. 自动扫描 刚开始扫描的时候适合用这种方式.有助于,理解整个网站的结构. 需要注意的是:去伪静态和业务冗余 伪静态 url结构相 ...

  2. ModelProxy 前端接口配置建模框架

    ModelProxy    轻量级的接口配置建模框架(1) 先看一下这个博客说明为什么需要用ModelProxy的前端轻量级的框架吧:  http://developer.51cto.com/art/ ...

  3. sql脚本比较大,sqlserver 无法导入,就用cmd命令执行

    osql简单用法:用来将本地脚本执行,适合sql脚本比较大点的情况,执行起来比较方便 1 osql -S serverIP -U sa -P 123 -i C:\script.sql serverIP ...

  4. Bootstrap3.0学习第九轮(CSS补充)

    详情请查看http://aehyok.com/Blog/Detail/15.html 个人网站地址:aehyok.com QQ 技术群号:206058845,验证码为:aehyok 本文文章链接:ht ...

  5. 每天一个linux命令(19):Linux 目录结构

    对于每一个Linux学习者来说,了解Linux文件系统的目录结构,是学好Linux的至关重要的一步.,深入了解linux文件目录结构的标准和每个目录的详细功能,对于我们用好linux系统只管重要,下面 ...

  6. MyEclipse8.5快速搭建SSH框架

    来源于:http://jingyan.baidu.com/article/a378c960a78125b3282830cc.html MyEclipse8.5快速搭建SSH框架 使用版本: Strut ...

  7. javaSE文件的使用

    1. package com.io.File; import java.io.*; import java.util.Date; public class UseFile { /** * 一些File ...

  8. Java-人民币转成大写

    /** * 人民币转成大写 hangeToBig * * @param value * @return String */ public static String 人民币转成大写(double va ...

  9. BZOJ-1207 打鼹鼠 DP(LIS)

    1207: [HNOI2004]打鼹鼠 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 2276 Solved: 1116 [Submit][Statu ...

  10. 高斯混合聚类及EM实现

    一.引言 我们谈到了用 k-means 进行聚类的方法,这次我们来说一下另一个很流行的算法:Gaussian Mixture Model (GMM).事实上,GMM 和 k-means 很像,不过 G ...