java基础知识总结(14)
下面再来看一个更加实际的例子——卫生间问题。
例 如火车上车厢的卫生间,为了简单,这里只模拟一个卫生间,这个卫生间会被多个人同时使用,在实际使用时,当一个人进入卫生间时则会把卫生间锁上,等出来时打开门,下一个人进去把门锁上,如果有一个人在卫生间内部则别人的人发现门是锁的则只能在外面等待。从编程的角度来看,这里的每个人都可以看作是一个线程 对象,而这个卫生间对象由于被多个线程访问,则就是临界资源,在一个线程实际使用时,使用synchronized关键将临界资源锁定,当结束时,释放锁定。实现的代码如下:
package syn3;
/**
*测试类
*/
public class TestHuman {
public static void main(String[] args) {
Toilet t = new Toilet(); //卫生间对象
Human h1 = new Human("1",t);
Human h2 = new Human("2",t);
Human h3 = new Human("3",t);
}
}
package syn3;
/**
*人线程类,演示互斥
*/
public class Human extends Thread {
Toilet t;
String name;
public Human(String name,Toilet t){
this.name = name;
this.t = t;
start(); //启动线程
}
public void run(){
//进入卫生间
t.enter(name);
}
}
package syn3;
/**
*卫生间,互斥的演示
*/
public class Toilet {
public synchronized void enter(String name){
System.out.println(name + "已进入!");
try{
Thread.sleep(2000);
}catch(Exception e){}
System.out.println(name + "离开!");
}
}
该示例的执行结果为,不同次数下执行结果会有所不同:
1已进入!
1离开!
3已进入!
3离开!
2已进入!
2离开!
在该示例代码中,Toilet类表示卫生间类,Human类模拟人,是该示例中的线程类,TestHuman类是测试类,用于启动线程。在TestHuman中,首先创建一个Toilet类型的对象t,并将该对象传递到后续创建的线程对象中,这样后续的线程对象就使用同一个Toilet对象,该对象就成为了临界资源。下面创建了三个Human类型的线程对象,每个线程具有自己的名称name参数,模拟3个线程,在每个线程对象中,只是调用对象t中的enter方法,模拟进入卫生间的动作,在enter方法中,在进入时输出调用该方法的线程进入,然后延迟2秒,输出该线程离开,然后后续的一个线程进入,直到三个线程都完成enter方法则程序结束。
在该示例中,同一个Toilet类的对象t的enter方法由于具有synchronized修饰符修饰,则在多个线程同时调用该方法时,如果一个线程进入到enter方法内部,则为对象t上锁,直到enter方法结束以后释放对该对象的锁定,通过这种方式实现无论多少个Human类型的线程,对于同一个对象t,任何时候只能有一个线程执行enter方法,这就是解决多线程问题的第一种思路——互斥的解决原理。