博学谷——让IT教学更简单,让IT学习更有效
2) 在Demo类中覆写run()方法,在方法内编写一个for循环,循环体内打印:线程名称+循环
次数。
3) 编写测试类Example07,在Example07类的main()方法中,创建一个Demo对象,利用Thread
的构造方法创建两个线程对象,分别命名“排队队员”和“插队队员”,然后编写两个线程对象的start()方法,然后调用“插队队员”线程的join()方法。
二、案例实现
class Demo implements Runnable { }
public class Example07 { }
public static void main(String[] args) { }
Demo jd = new Demo(); Thread t1 = new Thread(jd); Thread t2 = new Thread(jd); t1.setName(\排队队员\t2.setName(\插队队员\t1.start(); t2.start(); try { }
t2.join();
e.printStackTrace();
} catch (InterruptedException e) { public void run() { }
for (int x = 0; x < 5; x++) { }
System.out.println(Thread.currentThread().getName() + \
运行结果如图5-7所示。
图5-7
运行结果
11
博学谷——让IT教学更简单,让IT学习更有效
三、案例总结
1、线程插队,可以让插队的线程先执行完,然后本线程才开始执行。 2、使用线程插队join()方法时,需要抛出InterruptedException异常。
案例5-8 同步代码块的使用
一、案例描述
1、 考核知识点
编 号:00105012 名 称:同步代码块
2、 练习目标
? 掌握同步代码块作用
? 掌握同步代码块的使用方法 ? 掌握同步代码块中锁对象的使用
3、 需求分析
生活中,会遇到两人上洗手间的问题,甲使用洗手间的时候会锁上门,乙看到门锁上了,就需要等甲使用完后再使用的。那么在多线程程序中,可以通过将共享资源放在同步代码块内来实现多个线程同步处理共享资源的问题。本案例将通过两个线程共享资源来演示同步代码块的使用。
4、 设计思路(实现原理)
1) 自定义一个类Demo,使其实现Runnable接口。 2) 在Demo类中覆写run()方法,在方法内编写synchronized同步代码块,在进入同步代码块时,
打印线程名称,然后编写一个for循环,循环体内打印:运行线程名称+循环次数。当循环次数等于3时,跳出循环。 3) 编写测试类Example08,在Example08类的main()方法中,创建一个Demo对象,利用Thread
的构造方法创建两个线程对象,分别命名“张三”和“李四”,执行两个线程的start()方法。
二、案例实现
class Demo implements Runnable {
private Object obj = new Object(); public void run() {
synchronized (obj) {
System.out.println(Thread.currentThread().getName()
+ \进入洗手间,门以锁上\
for (int i = 1; i < 10; i++) {
System.out.println(Thread.currentThread().getName()
+ \正在使用洗手间\
if (i == 3) {
12
博学谷——让IT教学更简单,让IT学习更有效
}
public class Example08 { }
public static void main(String[] args) { }
Demo d = new Demo();
Thread t1 = new Thread(d, \张三\Thread t2 = new Thread(d, \李四\t1.start(); t2.start(); }
}
}
}
System.out.println(Thread.currentThread().getName()
+ \用完,准备出去,锁打开\
break;
运行结果如图5-8所示。
图5-8
运行结果
三、案例总结
1、同步代码块中的锁对象可以是任意类型的对象,但多个线程共享的锁对象必须是唯一的。
2、锁对象的创建代码不能放到run()方法中,否则每个线程运行到run()方法都会创建一个新对象,这样每个线程都会有一个不同的锁,每个锁都有自己的标志位。线程之间便不能产生同步的效果。
案例5-9 同步代码块嵌套造成死锁
一、案例描述
1、 考核知识点
编 号:00105014 名 称:死锁
2、 练习目标
? 了解什么是死锁和造成死锁的原因
13
博学谷——让IT教学更简单,让IT学习更有效
3、 需求分析
在编写多线程程序中,经常出现多个同步代码块嵌套的情况,而此时如果没有控制好锁对象的一致性就会出现死锁现象,接下来,在案例中通过同步代码块之间的互相嵌套来演示线程死锁。
4、 设计思路(实现原理)
1) 自定义一个类DieLock,使其继承Thread。
2) 在DieLock类中创建两个静态常量objA、objB,分别是a锁、b锁。然后创建一个boolean
类型的私有属性flag作为标示符,并编写DieLock的构造方法
3) 重写run()方法,在方法内首先判断flag的值。当flag值为true时,分别以objA和objB 为
锁对象,编写两个嵌套的同步代码块,并在同步代码块中打印flag值和锁对象名称;当flag为值为false时,编写flag为false时的代码,只是把锁对象的顺序更换一下。
4) 编写测试类Example09,在Example09类的main()方法中,利用DieLock的构造方法,创建
两个DieLock对象,传入的flag值分别为true和false,执行两个线程的start()方法。
二、案例实现
class DieLock extends Thread { }
public class Example09 {
public static void main(String[] args) {
new DieLock(true).start();
14
private boolean flag;
static Object objA = new Object(); static Object objB = new Object(); public DieLock(boolean flag) { }
public void run() { }
if (flag) { }
synchronized (objA) { }
synchronized (objB) { }
System.out.println(\synchronized (objA) { }
System.out.println(\System.out.println(\synchronized (objB) { }
System.out.println(\
this.flag = flag;
} else {
博学谷——让IT教学更简单,让IT学习更有效
}
new DieLock(false).start(); }
运行结果如图5-9所示。
图5-9
运行结果
三、案例总结
当两个线程的同步代码块彼此拿着对方需要的锁时,程序不会停止,但会一直“卡顿”,这种现象就是“死锁”现象。
案例5-10 多线程通信
一、案例描述
1、 考核知识点
编 号:00105015 名 称:多线程通信
2、 练习目标
? 掌握如何解决线程通信中的共享资源的安全问题
3、 需求分析
一条生产线的上下两个工序,它们必须以规定的速率完成各自的工作,才能保证产品在流水线中顺利的流转。在多线程的程序中,上下工序可以看作两个线程,这两个线程之间需要协同完成工作,就需要线程之间进行通信。了让初学者掌握多线程通信,案例中将通过生产和消费鼠标这两个过程的多线程协调来演示。
4、 设计思路(实现原理)
1) 创建一个产品类Product,该类有三个属性分别是:产品名称name,产品数量count,和一个boolean类型的标示量flag。当flag值为false时,说明产品未生产,当flag值为true时,说明产品已生产。
2) 在Product类中编写一个同步方法set(),每次调用set()方法时,表示要生成一个产品。在set()方法中,编写一个while循环,当flag值为true时,调用该线程的wait()方法,让线程等待。在while循环体外,count值递增,并打印当前线程名称和产品名称及数量,最后将flag值设为true,并唤醒所有的线程。
3) 在Product类中编写一个同步方法get(),每次调用get()方法时,表示要消费一件产品。在get()方法中,编写一个while循环,当flag值为false时,调用该线程的wait()方法,让线程等待。在循环体外,打印当前线程名称和被消费的产品名称和个数。最后将flag值设为false,并唤醒所有的线程。
4) 编写一个生产类Producter,该类定义了一个Product类型的成员变量和有参构造方法,构造方法中的参数用于为Product对象赋值,并且Producter类实现了Runnable接口。
15