第13章 多线程编程
13.1 多线程的五种基本状态
实例222 启动线程
package Chapter17.status;
import java.util.Date;
public class ThreadLife {
public void startY() {
ThreadY ty = new ThreadY();// 创建实例
ty.startThreadY(); // 启动ThreadY线程
try {
Thread.sleep(1000); // 当前线程休眠一秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
ty.stopThreadY(); // 停止ThreadY线程
}
public void startX() { // 开始第二个
Runnable runnX = new ThreadX(); // 创建实例
Thread threadX = new Thread(runnX); // 将实例放入线程中
threadX.start(); // start方法启动线程
}
public static void main(String[] args) { // java程序主入口处
ThreadLife test = new ThreadLife(); // 实例化对象
test.startY(); // 调用方法
test.startX();
}
}
class ThreadY extends Thread { // 继承java.lang.Thread类定义线程
private boolean isRunState = false; // 标记线程是否需要运行
public void start() { // 覆盖了父类的start方法,
this.isRunState = true; // 将isRunState置为ture,表示线程需要运行
super.start();
}
public void run() {
int i = 0;
try {
while (isRunState) { // 如果isRunState为真,说明线程还可以继续运行
this.setName("Thread-" + i++);
System.out.println("线程Y:" + this.getName() + " 正在运行");
Thread.sleep(200); // sleep方法将当前线程休眠。
}
} catch (Exception e) { // 捕获异常
}
System.out.println(this.getName() + "运行结束...");
}
public void setRunning(boolean isRunState) { // 设置线程
this.isRunState = isRunState;
}
public void startThreadY() { // 启动ThreadY线程
System.out.println("启动线程Y...");
this.start();
}
public void stopThreadY() { // 停止ThreadY线程
System.out.println("结束线程Y...");
this.setRunning(false);
}
}
class ThreadX implements Runnable { // 实现java.lang.Runnable接口定义线程
private Date runDate; // 线程被运行的时刻
public void run() {
System.out.println("线程X已经启动...");
this.runDate = new Date();
System.out.println("启动时间:" + runDate.toLocaleString());
}
}
实例223 参赛者的比赛生活(线程休眠唤醒)
package Chapter17.status;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Relay extends Thread {
private DateFormat df = new SimpleDateFormat("ss:SS");
public static void main(String[] args) { // java程序主入口处
Relay relay = new Relay(); // 实例化对象
relay.start(); // 启动线程
try {
relay.join(); // 等待线程运行结束
} catch (InterruptedException e) { // 捕获唤醒异常
System.out.println(" 收到命令,准备上场:" + e.getMessage());
}
relay.incident(); // 调用方法判断是否唤醒
}
public void incident() {
Thread.currentThread().interrupt(); // 唤醒当前线程
while (true) {
if (Thread.currentThread().isInterrupted()) { // 判断当前线程是否被唤醒
System.out.print(df.format(new Date()) + " 现在是否正在准备上场? ");
System.out.println(Thread.currentThread().isInterrupted() ? "是"
: "没有");
try {
Thread.currentThread().sleep(3000); // 线程休眠3秒
} catch (InterruptedException e) { // 捕获唤醒异常
System.out.println(df.format(new Date()) + " 收到命令,停止休息:"
+ e.getMessage());
}
System.out.print(df.format(new Date()) + " 比赛结束后是否参加下一轮比赛? ");
System.out.println(Thread.currentThread().isInterrupted() ? "是"
: "不参加");
}
}
}
public void run() {
System.out.println("第一场比赛结束的时间为:" + df.format(new Date()));
System.out.println("休息5小时");
try {
sleep(2000); // 线程休眠2秒 在程序假设1秒钟=1小时
} catch (InterruptedException e) { // 捕获唤醒异常
System.out.println(df.format(new Date()) + "收到命令,准备上场:"
+ e.getMessage());
}
System.out.print(df.format(new Date()) + " 在休息的过程中是否又参加其他的比赛? ");
try {
sleep(2000); // 线程休眠2秒
} catch (InterruptedException e) { // 捕获唤醒异常
System.out.println(df.format(new Date()) + "收到命令,准备上场:"
+ e.getMessage());
}
System.out.println(!isAlive() ? "参加比赛" : "没有参加其他的比赛"); // 线程是否激活,false表不是激活的
interrupt();// 唤醒线程
System.out.print(df.format(new Date()) + " 休息中,替补队员受伤,是否参加比赛? ");
System.out.println(isAlive() ? "参加比赛" : "不参加比赛"); // 线程是否激活
}
}
实例224 资源搜索并下载(线程等待和通报)
package Chapter17.status;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
public class ResourceFile {
private static boolean isStop = false; // 标识线程是否停止
private static List taskList = new ArrayList(); // 创建集合列表对象
private static DateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
private class SearchDownload extends Thread {// 创建模拟搜索资源并下载文件类
private String[] file = new String[] { "51Upload_Setup.exe",
"eclipse-SDK-3.2.1-win32.zip", "EditPlus.rar" };
// 创建模拟下载时所搜索的资源内容
private String[] resource = new String[] { "开始连接......",
"开始搜索候选资源......", "没搜索到候选资源,稍后重试搜索",
"原始资源连接成功,得到的文件长度: 7725816", "开始创建文件......",
"文件创建成功,开始下载数据......", "用户取消下载" };
int sum = 0;//下载一个任务时用的总时间
int time = 0;//搜索一个资源时用的时间
public void run() {// 实现线程类的方法
for (int i = 0; i < file.length; i++) {
System.out.println("开始下载第" + (i + 1) + "个文件");
try {
for (int j = 0; j < resource.length; j++) {
System.out.println(dateFormat.format(new Date()) + " "
+ resource[j]);
time = new Random().nextInt(100); // 获得随机生成的秒数
Thread.sleep(time); // 线程休眠等待
sum = sum + time;
}
System.out.println(dateFormat.format(new Date()) + " 下载文件"
+ file[i] + "用时" + sum + " 毫秒. ");
Thread.sleep(time); // 线程休眠等待
} catch (Exception e) { // 捕获异常
System.out.println("下载文件出错:" + e.getMessage());
}
synchronized (taskList) { // 实现同步
System.out.println(dateFormat.format(new Date()) + " "
+ file[i] + "文件已下载完毕!");
taskList.add(file[i]); // 将文件添加到集合列表中
taskList.notify(); // 通报所有等待的fileList的线程
}
sum = 0;
}
isStop = true; // 重新设置标识
System.out.println(dateFormat.format(new Date()) + " 下载线程 退出");
}
}
public static void main(String[] args) { // java程序主入口处
ResourceFile text = new ResourceFile(); // 实例化对象
text.new SearchDownload().start(); // 实例化内部类并启动线程
}
}
实例225 模拟淘宝购物买卖双方交易问题
package Chapter17;
import java.util.Random;
public class OnlineStore {
public static void main(String[] args) {
Alipay alipay = new Alipay(2); // 创建2个支付宝
// 创建实例并启动线程
new Seller("卖家-nieqing13", alipay, 5).start();
new Seller("卖家-小不不88", alipay, 7).start();
new Buyer("买家-淘之妖妖", alipay, 101).start();
new Buyer("买家-相信美丽", alipay, 102).start();
}
}
class Alipay { // 支付宝 用于网上买卖交易
private final String[] goods;//标识卖家商品,数组的长度是多少则表示商品的数量是多少
private int n; // 标识存入支付宝的交易数量
private int m; // 标识支出支付宝的交易数量
private int count; // 缓存内的交易数量
public Alipay(int count) { // 构造方法进行初始化
this.goods = new String[count]; // 创建字符串数组
this.m = 0;
this.n = 0;
this.count = 0;
}
public synchronized void storage(String alipay) { // 往支付宝里存款
System.out.println("淘宝用户ID=" + Thread.currentThread().getName()
+ "\t支付宝存入" + alipay);
try {
while (count >= goods.length) {
wait(); // 线程等待
}
goods[n] = alipay; // 放置支付宝账号于数组
n = (n + 1) % goods.length;
count++;
notifyAll();
} catch (Exception e) { // 捕获异常
System.out.println("支付宝存入功能出现错误:" + e.getMessage());
}
}
public synchronized String outlay() { // 从支付宝中支出
String alipay = null;
try {
while (count <= 0) {
wait(); // 线程等待
}
alipay = goods[m]; // 取出指定的支付宝账号
m = (m + 1) % goods.length;
count--; // 数组个数减一
notifyAll();
} catch (Exception e) { // 捕获异常
System.out.println("支付宝支付功能出现错误:" + e.getMessage());
}
System.out.println("淘宝用户ID=" + Thread.currentThread().getName()
+ "\t支付宝支出" + alipay);
return alipay;
}
}
class Buyer extends Thread { // 买家线程类
private final Random random;
private final Alipay alipay;
private static int id = 0; // 交易的流水号
public Buyer(String name, Alipay alipay, long seed) {// 构造方法进行初始化
super(name);
this.alipay = alipay;
this.random = new Random(seed);
}
public void run() { // 实现Thread类的方法,启动线程
try {
while (true) {
Thread.sleep(random.nextInt(1000));// 随机休眠
String flowerID = "交易流水账号:" + nextId();
alipay.storage(flowerID); // 存入支付宝中
}
} catch (Exception e) { // 捕获异常
}
}
private static synchronized int nextId() {
return id++;
}
}
class Seller extends Thread { // 卖家线程类
private final Random random;
private final Alipay alipay;
// 构造方法进行初始化
public Seller(String name, Alipay alipay, long seed) {
super(name);
this.alipay = alipay;
this.random = new Random(seed); // 创建随机对象
}
public void run() { // 实现Thread类的方法,启动线程
try {
while (true) {
String alipay = this.alipay.outlay();
Thread.sleep(random.nextInt(1000));
}
} catch (Exception e) { // 捕获异常
System.out.println("买家支付预付款出错:" + e.getMessage());
}
}
}
实例226 携子之手 与子偕老(join)
package Chapter17;
public class Partner {
/**
* @param args
*/
public static void main(String[] args) {
MatchMarry group1 = new MatchMarry("TOM", "SUSAN"); // 实例化对象
MatchMarry group2 = new MatchMarry("张三", "李小红");
MatchMarry group3 = new MatchMarry("安妮", "罗卜特·波伊尔");
MatchMarry group4 = new MatchMarry("TOM", "安妮");
MatchMarry group5 = new MatchMarry("SUSAN", "张三");
System.out.println("**速配婚姻介绍所,宗旨是要保证发扬\"携子之手 与子偕老\"的精神");
group1.start(); // 启动线程
try {
group1.join(); // 等待线程运行结束
} catch (InterruptedException e) { // 捕获唤醒异常
System.out.println("唤醒异常:" + e.getMessage());
}
group2.start();
try {
group2.join(); // 等待线程运行结束
} catch (InterruptedException e) { // 捕获唤醒异常
System.out.println("唤醒异常:" + e.getMessage());
}
group3.start();
try {
group3.join(); // 等待线程运行结束
} catch (InterruptedException e) { // 捕获唤醒异常
System.out.println("唤醒异常:" + e.getMessage());
}
group4.start();
try {
group4.join(); // 等待线程运行结束
} catch (InterruptedException e) { // 捕获唤醒异常
System.out.println("唤醒异常:" + e.getMessage());
}
group5.start();
try {
group5.join(); // 等待线程运行结束
} catch (InterruptedException e) { // 捕获唤醒异常
System.out.println("唤醒异常:" + e.getMessage());
}
System.out.println("速配结束...");
}
}
class MatchMarry extends Thread { // 测试匹配结婚的类
private String name; // 人员名称
private String otherName; // 结婚对象
private boolean isMarry = false; // 是否结婚
public MatchMarry(String name, String otherName) { // 带参数构造方法进行初始化
this.name = name;
this.otherName = otherName;
}
public void run() {
try {
int person = (int) Math.floor((Math.random() * 10 + 1));// 获得随机数
if (person % 2 == 0) {
isMarry = true; // 设置标识
} else {
isMarry = false;
}
if (!isMarry) {
System.out.println(name + "可以与" + otherName + "结婚,祝福你们");
} else {
System.out.println(otherName + "已婚,红色警告:对待婚姻不要有二心");
}
Thread.sleep(200); // 线程休眠
} catch (InterruptedException e) { // 捕获唤醒异常
System.out.println("唤醒异常:" + e.getMessage());
}
}
}
实例227 线程让步(Yield)
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Vector;
public class TextThreadYield { // 操作线程让步的类
private Vector vector = new Vector(); // 创建向量集合
// 创建日期格式
private DateFormat dateFormat = new SimpleDateFormat("HH-mm-ss:SSSS");
private boolean isFlag = false;
private class Yield extends Thread { //让步接收文件类
public Yield() {
this.setName("接收文件"); //设置线程名称
this.setDaemon(true); // 如果SendFile线程结束,则该线程自动结束
}
public void run() {
while (!isFlag) { // 标识为真进行循环
try {
Thread.sleep(100); // 休眠
}catch(InterruptedException e){ //捕获唤醒异常
System.out.println("唤醒异常:"+e.getMessage());
}
if (vector.size() == 0) { //判断向量集合大小
System.out.println(dateFormat.format(new Date())+ "\t向量集合中没有文件,执行yield操作");
Thread.yield(); //调用线程让步
} else { //移队文件获得对象
String ss = (String) vector.remove(0);
System.out.println(dateFormat.format(new Date())+"\t取到文件,名为" + ss);
}
}
}
}
private class SendFile extends Thread { //发送文件类
private String[] files = new String[] { "新闻文件", "国内旅游向导", "山水名画欣赏", "发家致富说明" };
public SendFile() {
this.setName("发送文件");
}
public void run() {
try {
for (int i=0;i < files.length;i++){ //循环使线程休眠
Thread.sleep(201); //线程休眠
vector.add(files[i]); //添加文件
}
Thread.sleep(100); //线程休眠
} catch (InterruptedException e) { //捕获唤醒异常
System.out.println("唤醒异常:"+e.getMessage());
}
}
}
public static void main(String []args){ //java程序主入口处
TextThreadYield text=new TextThreadYield();//实例化对象
text.new Yield().start(); //实例对象启动线程
text.new SendFile().start();
}
}
实例228 会走动的钟(多线程)
package Chapter17.status;
import java.applet.Applet;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.Date;
public class MoveClock extends Applet implements Runnable {
Thread hourThread = null; // 时针线程
Thread minuteThread = null; // 分针线程
Thread secondThread = null; // 秒针线程
int hourX, hourY, minuteX, minuteY, secondX, secondY;// 表示时,分,秒针端点的XY坐标点
int currentHour = 0; // 获取当前时间中代表小时的数字值
int currentMinute = 0; // 获取当前时间中代表分钟的数字值
int currentSecond = 0; // 获取当前时间中代表秒的数字值
Graphics secondGraphics = null; // 绘制秒针的Graphics对象
Graphics minuteGraphics = null; // 绘制分针的Graphics对象
Graphics hourGraphics = null; // 绘制时针的Graphics对象
Graphics2D minuteg2D = null; // 创建Graphics2D对象
Graphics2D hourg2D = null; // 创建Graphics2D对象
Graphics2D secondg2D = null; // 创建Graphics2D对象
double drawX[] = new double[61]; // 存放表盘刻度的X轴数组
double drawY[] = new double[61]; // 存放表盘刻度的Y轴数组
double dial_x[] = new double[61]; // 供绘制表盘使的x点坐标值
double dial_y[] = new double[61]; // 供绘制表盘使的Y点坐标值
int isRestart = 0; // 判断是否重新开始
public void init() { // 数据初始化
hourGraphics = this.getGraphics(); // 实例化时针Graphics对象
hourGraphics.setColor(Color.white); // 设置时针的颜色
hourg2D = (Graphics2D) hourGraphics; // 实例化时针Graphics2D对象
hourGraphics.translate(200, 200); // 进行坐标系统变换原点设在(200,200)处
minuteGraphics = this.getGraphics(); // 实例化分针Graphics对象
minuteg2D = (Graphics2D) minuteGraphics; // 实例化分针Graphics2D对象
minuteGraphics.setColor(Color.green); // 设置分针的颜色
minuteGraphics.translate(200, 200); // 进行坐标系统变换,原点设在(200,200)处
secondGraphics = this.getGraphics(); // 实例化秒针Graphics对象
secondg2D = (Graphics2D) secondGraphics; // 实例化秒针Graphics2D对象
secondGraphics.setColor(Color.blue); // 设置秒针的颜色
secondGraphics.translate(200, 200); // 进行坐标系统变换,原点设在(200,200)处
drawX[0] = 0;
// 各个时针12点处的位置坐标(按新坐标系的坐标)
drawY[0] = -120;
dial_x[0] = 0;
// 12点处的刻度位置坐标(按新坐标系的坐标)
dial_y[0] = -140;
double jiaodu = 6 * Math.PI / 180;
// 表盘分割成60分,将分割点的坐标存放在数组中
for (int i = 0; i < 60; i++) {
drawX[i + 1] = drawX[i] * Math.cos(jiaodu) - Math.sin(jiaodu)
* drawY[i];
drawY[i + 1] = drawY[i] * Math.cos(jiaodu) + drawX[i]
* Math.sin(jiaodu);
}
drawX[60] = 0;
drawY[60] = -120;
// 表盘分割成60分,将分割点的坐标存放在绘制数组中
for (int i = 0; i < 60; i++) {
dial_x[i + 1] = dial_x[i] * Math.cos(jiaodu) - Math.sin(jiaodu)
* dial_y[i];
dial_y[i + 1] = dial_y[i] * Math.cos(jiaodu) + Math.sin(jiaodu)
* dial_x[i];
}
dial_x[60] = 0;
dial_y[60] = -140;
}
public void start() {
if (isRestart >= 1) {
secondThread.interrupt(); // 唤醒线程
minuteThread.interrupt();
hourThread.interrupt();
}
hourThread = new Thread(this); // 创建时针线程
minuteThread = new Thread(this); // 创建分针线程
secondThread = new Thread(this); // 创建秒针线程
secondThread.start(); // 启动秒针线程
minuteThread.start(); // 启动分针线程
hourThread.start(); // 启动时针线程
isRestart++;
if (isRestart >= 2)
isRestart = 1;
}
public void stop() {
secondThread.interrupt(); // 唤醒线程
minuteThread.interrupt();
hourThread.interrupt();
}
public void paint(Graphics g) { // 绘制图形
this.setBackground(Color.black);
this.start();
g.drawOval(50, 50, 300, 300); // 表盘的外圈
g.translate(200, 200); // 进行坐标系统变换
for (int i = 0; i < 60; i++) { // 绘制表盘的小刻度和大刻度
if (i % 5 == 0) {
g.setColor(Color.red); // 设置颜色
g.fillOval((int) dial_x[i], (int) dial_y[i], 10, 10);
} else
g.fillOval((int) dial_x[i], (int) dial_y[i], 5, 5);
}
}
public void run() { // 实现Thread的方法,开始线程
Date date = new Date(); // 获取本地时间
String string = date.toString();
currentHour = Integer.parseInt(string.substring(11, 13)); // 获得当前时间的小时
currentMinute = Integer.parseInt(string.substring(14, 16)); // 获取当前时间的分钟
currentSecond = Integer.parseInt(string.substring(17, 19));// 获取当前时间的秒钟
if (Thread.currentThread() == secondThread) { // 如果当前线程是秒线程
secondX = (int) drawX[currentSecond]; // 秒针初始化
secondY = (int) drawX[currentSecond];
// 用背景色清除前一秒的秒针
secondGraphics.drawLine(0, 0, secondX, secondY);
secondg2D.setStroke(new BasicStroke(2.0f)); // 设置所绘制秒针的宽度
int i = currentSecond;
while (true) {
try {
secondThread.sleep(1000); // 每隔一秒休眠
Color c = getBackground(); // 获取背景颜色
secondGraphics.setColor(c); // 设置秒针的颜色
// 用背景色清除前一秒的秒针
secondGraphics.drawLine(0, 0, secondX, secondY);
secondg2D.setStroke(new BasicStroke(2.0f));
// 秒针与分针重合,恢复分针显示
if ((secondX == minuteX) && (secondY == minuteY)) {
// 用背景色清除前一分的分针
minuteGraphics.drawLine(0, 0, minuteX, minuteY);
}
// 秒针与时针重合,恢复时针的显示
if ((secondX == hourX) && (secondY == hourY)) {
// 用背景色清除前一时的时针
hourGraphics.drawLine(0, 0, hourX, hourY);
hourg2D.setStroke(new BasicStroke(4.0f));// 设置所绘制时针的宽度
}
} catch (InterruptedException e) { // 捕获异常
Color c = getBackground(); // 获取背景颜色
secondGraphics.setColor(c); // 设置秒针的颜色
// 用背景色清除秒针
secondGraphics.drawLine(0, 0, secondX, secondY);
secondg2D.setStroke(new BasicStroke(2.0f));
return;
}
secondX = (int) drawX[(i + 1) % 60]; // 秒针向前走一个单位
secondY = (int) drawY[(i + 1) % 60]; // 每一秒走6度(一个单位格)
secondGraphics.setColor(Color.blue); // 绘制秒针的颜色
// 用背景色清除前一秒的秒针
secondGraphics.drawLine(0, 0, secondX, secondY);
secondg2D.setStroke(new BasicStroke(2.0f));
i++;
}
}
if (Thread.currentThread() == minuteThread) { // 如果当前线程是分线程
minuteX = (int) drawX[currentMinute];
minuteY = (int) drawY[currentMinute];
minuteGraphics.drawLine(0, 0, minuteX, minuteY);
minuteg2D.setStroke(new BasicStroke(3.0f));
int i = currentMinute; // 获取当前分钟
while (true) {
try { // 第一次过60-second秒就前进一分钟,以后每过60秒前进一分钟
minuteThread.sleep(1000 * 60 - currentSecond * 1000);
currentSecond = 0;
Color c = getBackground(); // 获取背景颜色
minuteGraphics.setColor(c); // 设置分针的颜色
minuteg2D.setStroke(new BasicStroke(3.0f));// 设置所绘制分针的宽度
minuteGraphics.drawLine(0, 0, minuteX, minuteY);
// 如果时针和分针重合
if ((hourX == minuteX) && (hourY == minuteY)) {
hourGraphics.drawLine(0, 0, minuteX, minuteY);
hourg2D.setStroke(new BasicStroke(4.0f));
}
} catch (InterruptedException e) {
return;
}
minuteX = (int) drawX[(i + 1) % 60]; // 分针向前走一个单位
minuteY = (int) drawY[(i + 1) % 60]; // 每一分走6度(一个单位格)
minuteGraphics.setColor(Color.BLUE); // 绘制分针的颜色
minuteg2D.setStroke(new BasicStroke(3.0f));
minuteGraphics.drawLine(0, 0, minuteX, minuteY);
i++;
currentSecond = 0;
}
}
if (Thread.currentThread() == hourThread) { // 如果当前线程是时线程
int h = currentHour % 12;
hourX = (int) drawX[h * 5 + currentMinute / 12];
hourY = (int) drawY[h * 5 + currentMinute / 12];
int i = h * 5 + currentMinute / 12;
hourGraphics.drawLine(0, 0, hourX, hourY);
hourg2D.setStroke(new BasicStroke(4.0f));
while (true) {
try {
// 第一次过12-minute%12分钟就前进一个刻度,以后每过12分钟前进一刻度
hourThread.sleep(1000 * 60 * 12 - 1000 * 60
* (currentMinute % 12) - currentSecond * 1000);
currentMinute = 0;
Color c = getBackground();
hourGraphics.setColor(c);
hourGraphics.drawLine(0, 0, hourX, hourY);
hourg2D.setStroke(new BasicStroke(4.0f));
} catch (InterruptedException e) {
return;
}
hourX = (int) drawX[(i + 1) % 60];
hourY = (int) drawY[(i + 1) % 60];
hourGraphics.setColor(Color.BLACK);
hourGraphics.drawLine(0, 0, hourX, hourY);
hourg2D.setStroke(new BasicStroke(4.0f));
i++;
currentMinute = 0;
}
}
}
}
实例229 变形金刚中的守护神(守护线程)
package Chapter17.status;
public class Transformer { // 本程序的测试类
public static void main(String[] args) { // java程序执行入口处
Defensor defensor = new Defensor(); // 默认情况下父类Defensor是普通线程
defensor.start(); // 启动Defensor类线程
try {
Thread.sleep(500);
} catch (InterruptedException e) { // 捕获被唤醒异常
System.out.println("唤醒异常:" + e.getMessage());
}
}
}
class Defensor extends Thread { // 操作守护神线程的类
public void run() {
System.out.print("当霸天虎在袭击地球的危难关头,守护神是否采取自我保护? ");
System.out.println(this.isDaemon() ? "是" : "没有");// 测试该线程是否为守护线程。
System.out.println("守护神Defensor是机器卫兵的组合战士,个性善良,愿意牺牲自己去保护人类");
Human people = new Human();
people.setDaemon(true); // 设置守护线程,在本程序中将其子类people设置为守护线程也就是被保护的对象
people.start(); // 启动守护线程
try {
Thread.sleep(1000); // 休眠1秒
} catch (InterruptedException e) { // 捕获唤醒异常
System.out.println("唤醒异常:" + e.getMessage());
} finally { // 内容总执行
System.out.println("在面对危险的时候,守候神舍身捍卫地球,保护人类的安全");
}
System.out.println("守候神太伟大了...");
}
}
class Human extends Thread {
public void run() {
System.out.print("人类的安全是否被保护?");
System.out.println(this.isDaemon() ? "是" : "没有");// 判断此线程是否是守护线程
System.out.println("现在有5处场所的人们正处于危险之中!!!");
int i = 0;
try {
while (i < 5) { // 进行5次循环
System.out.println("第" + (1 + i++) + "处场所的人类");
Thread.sleep(200); // 休眠0.2秒
}
} catch (InterruptedException e) { // 捕获唤醒异常
System.out.println("唤醒异常:" + e.getMessage());
} finally { // 内容总执行
System.out.println("守候神尽心尽力,帮助人类安全的躲过霸天虎的疯狂袭击");
}
System.out.println("终于脱离危险了~~~");
}
}
实例230 查看JVM中所有的线程的活动状况
public class ThreadAction {// 操作查看JVM虚拟机中所的线程和线程组的类
// 显示线程信息
private static void threadMessage(Thread thread, String index) {
if (thread == null)
return;
System.out.println(index + "ThreadName- " + thread.getName()
+ " Priority- " + thread.getPriority()
+ (thread.isDaemon() ? " Daemon" : "")
+ (thread.isAlive() ? "" : " Inactive"));
}
// 显示线程组信息
private static void threadGroupMessage(ThreadGroup group, String index) {
if (group == null)
return; // 判断线程组
int count = group.activeCount(); // 获得活动的线程数
// 获得活动的线程组数
int countGroup = group.activeGroupCount();
// 根据活动的线程数创建指定个数的线程数组
Thread[] threads = new Thread[count];
// 根据活动的线程组数创建指定个数的线程组数组
ThreadGroup[] groups = new ThreadGroup[countGroup];
group.enumerate(threads, false); // 把所有活动子组的引用复制到指定数组中,false表示不包括对子组的所有活动子组的引用
group.enumerate(groups, false);
System.out.println(index + "ThreadGroupName-" + group.getName()
+ "MaxPriority- " + group.getMaxPriority()
+ (group.isDaemon() ? " Daemon" : ""));
// 循环显示当前活动的线程信息
for (int i = 0; i < count; i++)
threadMessage(threads[i], index + " ");
for (int i = 0; i < countGroup; i++)
// 循环显示当前活动的线程组信息
threadGroupMessage(groups[i], index + " ");// 递归调用方法
}
public static void threadsList() { // 找到根线程组并列出它递归的信息
ThreadGroup currentThreadGroup; // 当前线程组
ThreadGroup rootThreadGroup; // 根线程组
ThreadGroup parent;
// 获得当前活动的线程组
currentThreadGroup = Thread.currentThread().getThreadGroup();
rootThreadGroup = currentThreadGroup; // 获得根线程组
parent = rootThreadGroup.getParent(); // 获得根线程
while (parent != null) { // 循环对根线程组重新赋值
rootThreadGroup = parent;
parent = parent.getParent();
}
threadGroupMessage(rootThreadGroup, ""); // 显示根线程组
}
public static void main(String[] args) { // java程序主入口处
System.out.println("查看JVM中所有的线程的活动状况如下:");
ThreadAction.threadsList(); // 调用方法显示所有线程的信息
}
}
实例231 模仿网络快车下载工具下载文件
package Chapter17.status;
import java.awt.AWTEvent;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class FreshDownload extends JFrame {
private JPanel mainPanel; // 网络快车的主面板
private JTextField webField = new JTextField(); // 下载地址的文本框
private JTextField localFile = new JTextField(); // 下载到本地的文本框
private JTextField fileNameField = new JTextField(); // 文件名对应的文本框
private JTextField categoryField = new JTextField(); // 分类对应的文本框
private JButton button = new JButton(); // 下载按钮
private JButton button1 = new JButton(); // 取消下载按钮
private JLabel targetLabel = new JLabel(); // 目标标签
private JLabel localLabel = new JLabel(); // 下载到本地标签
private JLabel fileName = new JLabel(); // 下载的文件名
private JLabel category = new JLabel(); // 分类
private JLabel content = new JLabel(); // 信息内容
private JLabel tips = new JLabel(); // 信息提示
private JTextArea textArea = new JTextArea(); // 显示下载记录的文本域
private String urlPath = new String(); // 下载地址
private String saveFileAs = new String(); // 另存为
public FreshDownload() { // 构造方法进行初始化
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
initPanel(); // 调用方法初始化面板
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void initPanel() throws Exception { // 初始化面板
mainPanel = (JPanel) this.getContentPane(); // 创建面板
mainPanel.setLayout(null); // 没有设置面板布局
this.setSize(new Dimension(480, 420)); // 面板的大小
this.setLocation(100, 100); // 面板位置
this.setTitle("模仿网络快车多线程下载"); // 面板标题
targetLabel.setBounds(new Rectangle(20, 20, 120, 20)); // 标签的位置
targetLabel.setText("下载网址: ");
webField.setBounds(new Rectangle(100, 20, 250, 20)); // 设置文本框的位置
// 设置默认下载路径
webField.setText("http://zhanjia.javaeye.com/topics/download/d3682cdf-04be-3a57-89a4-93cbef5ae038");
fileName.setText("文件名:");
fileName.setBounds(20, 50, 120, 20);// 文件名标签的位置
fileNameField.setText("java实例.jar");// 文件文本框中默认的内容
fileNameField.setBounds(100, 50, 120, 20);// 文件文本框中的位置
category.setText("分类:");
category.setBounds(20, 80, 120, 20);// 分类标签的位置
categoryField.setText("其他");
categoryField.setBounds(100, 80, 120, 20);// 分类文本框中的位置
localLabel.setBounds(new Rectangle(20, 110, 120, 20)); // 标签的位置
localLabel.setText("下载到: ");
localFile.setBounds(new Rectangle(100, 110, 120, 20)); // 设置文本框的位置
localFile.setText("F:\\Downloads");// 设置默认另存为
button.setBounds(new Rectangle(230, 110, 60, 20)); // 按钮的位置
button.setText("下载");
button1.setBounds(new Rectangle(290, 110, 60, 20)); // 按钮的位置
button1.setText("取消");
tips.setBounds(new Rectangle(20, 130, 120, 20)); // 标签的位置
tips.setText("信息提示: ");
content.setText("F盘可用空间71.7GB,任务所需空间24.3MB");
content.setBounds(100, 130, 250, 20);
button.addActionListener(new ActionListener() { // 按钮添加监听事件
public void actionPerformed(ActionEvent e) {
getActionPerformed(e); // 调用事件
}
});
// 创建有滑动条的面板将文本域放在上面
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setBounds(new Rectangle(20, 160, 400, 200)); // 面板的位置
textArea.setEditable(false); // 不可编辑
mainPanel.add(webField, null); // 将文本框添加到面板中
mainPanel.add(localFile, null); // 将文本框添加到面板中
mainPanel.add(fileName, null);// 将文件名标签添加到面板中
mainPanel.add(fileNameField, null);// 将文件名文本框添加到面板中
mainPanel.add(category, null);// 将分类标签添加到面板中
mainPanel.add(categoryField, null);// 将分类文本框添加到面板中
mainPanel.add(targetLabel, null); // 将标签添加到面板中
mainPanel.add(localLabel, null); // 将标签添加到面板中
mainPanel.add(button, null); // 将下载按钮添加到面板中
mainPanel.add(button1, null); // 将取消按钮添加到面板中
mainPanel.add(tips, null); // 将标签添加到面板中
mainPanel.add(content, null); // 将标签添加到面板中
mainPanel.add(scrollPane, null); // 将滑动条添加到面板中
urlPath = webField.getText(); // 获得文本框中的文本
saveFileAs = localFile.getText();// 获得文本框中的文本
this.setDefaultCloseOperation(EXIT_ON_CLOSE); // 设置默认关闭操作
}
// 点击事件触发方法,启动分析下载文件的进程
public void getActionPerformed(ActionEvent e) {
urlPath = webField.getText(); // 获得目标文件的网址
saveFileAs = localFile.getText(); // 获得另存为的地址
if (urlPath.compareTo("") == 0)
textArea.setText("请输入要下载的文件完整地址");
else if (saveFileAs.compareTo("") == 0) {
textArea.setText("请输入保存文件完整地址");
} else {
try {
SearchAndDown downFile = new SearchAndDown(urlPath, saveFileAs,
5, textArea); // 传参数实例化下载文件对象
downFile.start(); // 启动下载文件的线程
textArea.append("主线程启动...");
} catch (Exception ec) { // 捕获异常
System.out.println("下载文件出错:" + ec.getMessage());
}
}
}
public static void main(String[] args) { // java程序主入口处
FreshDownload frame = new FreshDownload(); // 实例化对象进行初始化
frame.setVisible(true); // 设置窗口可视
}
}
class SearchAndDown extends Thread { // 分析下载的文件并启动下载进程
String urlPath; // 下载文件的地址
String saveFileAs; // 文件另存为
int threadCount; // 线程总数
String log = new String(); // 下载过程的日志记录
JTextArea textArea = new JTextArea(); // 创建文本域
long[] position;
long[] start; // 每个线程开始位置
long[] end; // 每个线程结束位置
BatchFile[] file; // 子线程对象
long fileLength; // 下载的文件的长度
public SearchAndDown(String urlPath, String saveFileAs, int threadCount,
JTextArea textArea) { // 构造方法进行初始化
this.urlPath = urlPath;
this.saveFileAs = saveFileAs;
this.threadCount = threadCount;
this.textArea = textArea;
start = new long[threadCount];
end = new long[threadCount];
}
public void run() { // 实现Thread类的方法
log = "目标文件: " + urlPath;
textArea.append("\n" + log); // 日志写入文本域
log = "\n 线程总数: " + threadCount;
textArea.append("\n" + log);
try {
fileLength = getSize(); // 获得文件长度
if (fileLength == -1) { // 不可获取文件长度或没找到资源
textArea.append("\n 不可知的文件长度!请重试!!");
} else {
if (fileLength == -2) { // 无法获取文件或没有找到资源
textArea.append("\n 文件无法获取,没有找到指定资源,请重试!!");
} else { // 循环对每个线程的开始位置赋值
for (int i = 0; i < start.length; i++) {
start[i] = (long) (i * (fileLength / start.length));
}
for (int i = 0; i < end.length - 1; i++)
// 循环对每个线程的结束位置赋值
end[i] = start[i + 1];
// 最后一线程结束位置是文件长度
end[end.length - 1] = fileLength;
for (int i = 0; i < start.length; i++) { // 循环显示每线程开始和结束位置
log = "线程:" + i + "下载范围:" + start[i] + "--" + end[i];
textArea.append("\n" + log);
}
file = new BatchFile[start.length];
for (int i = 0; i < start.length; i++) { // 启动一组子线程
file[i] = new BatchFile(urlPath, saveFileAs, start[i],
end[i], i, textArea);
log = "线程 " + i + "启动";
textArea.append("\n" + log);
file[i].start(); // 启动线程
}
boolean breakWhile = true;
while (breakWhile) { // 当条件始终为true时进行循环
Thread.sleep(500); // 线程休眠
breakWhile = false;
for (int i = 0; i < file.length; i++) {
if (!file[i].isDone) { // 循环判断每个线程是否结束
breakWhile = true;
break;
}
}
}
textArea.append("\n文件传输结束!");// 文件传输结束
}
}
} catch (Exception ex) { // 捕获异常
ex.printStackTrace();
}
}
public long getSize() { // 获得文件的长度的方法
int fileLength = -1;
try {
URL url = new URL(urlPath); // 根据网址创建URL对象
HttpURLConnection httpConnection = (HttpURLConnection) (url
.openConnection()); // 创建远程对象连接对象
int responseCode = httpConnection.getResponseCode();
if (responseCode >= 400) { // 没有获得响应信息
System.out.println("Web服务器响应错误");
return -2; // Web服务器响应错误
}
String sHeader;
for (int i = 1;; i++) { // 查标识文件长度文件头获文件长度
sHeader = httpConnection.getHeaderFieldKey(i);
if (sHeader != null) {
if (sHeader.equals("Content-Length")) {// 查找标识文件长度的文件头
fileLength = Integer.parseInt(httpConnection
.getHeaderField(sHeader));
break;
}
} else {
break;
}
}
} catch (Exception e) { // 捕获异常
System.out.println("无法获得文件长度:" + e.getMessage());
}
return fileLength;
}
}
class BatchFile extends Thread {
String urlPath; // 下载文件的地址
long start; // 线程的开始位置
long end; // 线程的结束位置
int threadID;
JTextArea textArea = new JTextArea(); // 创建文本域
boolean isDone = false; // 是否下载完毕
RandomAccessFile random;
public BatchFile(String urlPath, String saveAs, long nStart, long nEnd,
int id, JTextArea textArea) {
this.urlPath = urlPath;
this.start = nStart;
this.end = nEnd;
this.threadID = id;
this.textArea = textArea;
try {
random = new RandomAccessFile(saveAs, "rw"); // 创建随机访问对象,以读/写方式
random.seek(start); // 定位文件指针到startPosition位置
} catch (Exception e) { // 捕获异常
System.out.println("创建随机访问对象出错:" + e.getMessage());
}
}
public void run() { // 实现Thread类的方法
try {
URL url = new URL(urlPath); // 根据网址创建URL对象
HttpURLConnection httpConnection = (HttpURLConnection) url
.openConnection(); // 创建远程对象连接对象
String sProperty = "bytes=" + start + "-";
httpConnection.setRequestProperty("RANGE", sProperty);
textArea.append("\n 线程" + threadID + "下载文件! 请等待...");
InputStream input = httpConnection.getInputStream();// 获得输入流对象
byte[] buf = new byte[1024]; // 创建字节数据存储文件的数据
int splitSpace;
splitSpace = (int) end - (int) start; // 获得每个线程的间隔
if (splitSpace > 1024)
splitSpace = 1024;
// 读取文件信息
while (input.read(buf, 0, splitSpace) > 0 && start < end) {
splitSpace = (int) end - (int) start;
if (splitSpace > 1024)
splitSpace = 1024;
textArea.append("\n线程: " + threadID + " 开始位置: " + start
+ ", 间隔长度: " + splitSpace);
random.write(buf, 0, splitSpace); // 写入文件
start += splitSpace; // 开始位置改变
}
textArea.append("\n 线程" + threadID + "下载完毕!!");
random.close(); // 释放资源
input.close();
isDone = true;
} catch (Exception e) { // 捕获异常
System.out.println("多线程下载文件出错:" + e.getMessage());
}
}
}
13.2 多线程的同步与互斥
实例232 多线程同步方法的实例
package Chapter17;
public class SyncExample {
public static void main(String[] args) {
SyncThread t1 = new SyncThread(); // 创建SyncThread类的实例对象
new Thread(t1, "线程1").start(); // 创建线程并启动它
new Thread(t1, "线程2").start(); // 创建线程并启动它
System.out.println(t1.Perform()); // 调用SyncThread类的同步方法call()
}
}
class SyncThread implements Runnable {
private int x = 5;
private int y = 5;
// 定义SyncThread的同步方法
public synchronized void run() { // 重写Runnable接口的run(),并声明成synchronized
for (int i = 0; i < 4; i++) {
x++;
y++;
try {
Thread.sleep(200); // 当前运行的线程休眠200毫秒
} catch (InterruptedException e) {
System.out.println("线程出错了");
}
System.out.println(Thread.currentThread().getName() + " x=" + x
+ ",y=" + y);
}
}
public synchronized String Perform() { // 自定义方法,并声明成synchronized
String name = Thread.currentThread().getName();
return "当前正在运行的线程: " + name;
}
}
实例233 ATM存取一体机(线程同步互斥)
package Chapter17;
public class ATMCashMachines {
public static void main(String[] args) { // java程序主入口处
Bank bank = new Bank();// 实例化Bank对象
SyncBank sbank = new SyncBank();// 实例化SyncBank对象
System.out.println("1.存、取线程没有采取同步时,执行存取操作时,其工作流程如下:");
// 存钱没有采用同步机制
Thread putThread = new CashMachines(bank, "saveMoney");
// 取钱没有同步机制
Thread takeThread = new CashMachines(bank, "withdrawMoney");
putThread.start(); // 启动putThread线程
takeThread.start(); // 启动takeThread线程
try {
putThread.join(); // 等待两线程运行结束
takeThread.join();
} catch (Exception e) { // 捕获异常
System.out.println("两线程运行出错:" + e.getMessage());
}
System.out.println();
bank = new Bank();
System.out.println("2.存、取线程设置为同步时,执行存取操作时,其工作流程如下:");
putThread = new CashMachines(sbank, "sync_SaveMoney"); // 创建CashMachines对象,存钱有同步机制
takeThread = new CashMachines(sbank, "sync_WithdrawMoney"); // 取钱有同步机制
putThread.start(); // 启动线程
takeThread.start(); // 启动线程
}
}
class Bank {
private double curveMoney = 174.85; // 存入银行的钱数
public void saveMoney(double putThread) { // 存钱没有采用同步机制
System.out.println("当前账户中所剩余额为" + this.curveMoney + "; 存入金额为: "
+ putThread);
System.out.println("正在操作,请稍候......"); // 存钱时先等待300毫秒
try {
Thread.sleep(300); // 线程休眠
} catch (Exception e) { // 捕获异常
e.printStackTrace();
}
System.out.println("操作成功,存入金额:" + putThread);
this.curveMoney = this.curveMoney + putThread;
System.out.println("当前余额为:" + this.curveMoney + "元");
}
public void withdrawMoney(double takeThread) { // 取钱没有同步机制
System.out.println("查询余额显示,当前可用余额为:" + this.curveMoney + "; 取出金额为: "
+ takeThread);
System.out.println("正在操作,请稍候......"); // 取钱时先等待500毫秒
try {
Thread.sleep(500); // 线程休眠
} catch (Exception e) { // 捕获异常
e.printStackTrace();
}
System.out.println("操作成功,取出金额:" + takeThread);
this.curveMoney = this.curveMoney - takeThread;
System.out.println("当前余额为:" + this.curveMoney + "元");
}
}
class SyncBank {
private double curveMoney = 174.85; // 存入银行的钱数
public synchronized void sync_SaveMoney(double putThread) { // 存钱有同步机制
System.out.println("当前账户中所剩余额为" + this.curveMoney + "; 存入金额为: "
+ putThread);
System.out.println("正在操作,请稍候......"); // 存钱时先等待300毫秒
try {
Thread.sleep(300); // 线程休眠
} catch (Exception e) { // 捕获异常
e.printStackTrace();
}
System.out.println("操作成功,存入金额:" + putThread);
this.curveMoney = this.curveMoney + putThread;
System.out.println("当前余额为:" + this.curveMoney + "元");
}
public synchronized void sync_WithdrawMoney(double takeThread) {// 取钱有同步机制
System.out.println("查询余额显示,当前可用余额为:" + this.curveMoney + "; 取出金额为: "
+ takeThread);
System.out.println("正在操作,请稍候......"); // 取钱时先等待500毫秒
try {
Thread.sleep(500); // 线程休眠
} catch (Exception e) { // 捕获异常
e.printStackTrace();
}
System.out.println("操作成功,取出金额:" + takeThread);
this.curveMoney = this.curveMoney - takeThread;
System.out.println("当前余额为:" + this.curveMoney + "元");
}
}
class CashMachines extends Thread { // 继承Thread类实现线程方法
private Bank bank = null; // 待访问的帐号对象
private SyncBank sbank = null; // 待访问的帐号对象
private String account = ""; // 访问帐号的方法
public CashMachines(Bank bank, String account) { // 构造方法进行初始化
this.account = account;
this.bank = bank;
}
public CashMachines(SyncBank sbank, String account) { // 构造方法进行初始化
this.account = account;
this.sbank = sbank;
}
public void run() { // 实现Thread的方法
if (account.equals("saveMoney")) { // 不同参数调用不同的方法
bank.saveMoney(800.0);
} else if (account.equals("withdrawMoney")) {
bank.withdrawMoney(300.0);
} else if (account.equals("sync_SaveMoney")) {
sbank.sync_SaveMoney(800.0);
} else if (account.equals("sync_WithdrawMoney")) {
sbank.sync_WithdrawMoney(300.0);
}
}
}
实例234 我的钱哪里去了
package Chapter17;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class SavingOffice extends Frame implements ActionListener {
private Label label = new Label("转账已完成:0");
// 创建AWT多行文本组件
private TextArea area = new TextArea();
// 创建AWT按扭组件
private Button display = new Button("显示帐户");
private Button start = new Button("重新启动");
private Button stop = new Button("停止");
// 声明账号的个数
protected final static int num_accounts = 8;
// 定义浪沸的时间
private final static int waste_time = 1;
// 创建一个int型数组,用于存入账号的初始金额
private int accounts[] = new int[num_accounts];
// 创建一个Customer数组,用于存放Customer实例化对象
private Customer customer[] = new Customer[num_accounts];
// 表法转账的金额
private int count = 0;
public SavingOffice() {// 构造方法,为其AWT成员变量进行初始化
super("我的秘密小金库");
Panel btn_Panel = new Panel();
btn_Panel.setLayout(new FlowLayout());
btn_Panel.add(display);
display.addActionListener(this);
btn_Panel.add(start);
start.addActionListener(this);
btn_Panel.add(stop);
stop.addActionListener(this);
setLayout(new BorderLayout());
add("North", label);
add("South", btn_Panel);
add("Center", area);
for (int i = 0; i < accounts.length; i++)
accounts[i] = 50000;// 每个账户上的初始金额为5万元
start();// 是普通的方法,并非线程的start方法
validate();
setSize(300, 300);
setVisible(true);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
}
public void transfer(int from, int into, int amount) {// 进行转账
if ((accounts[from] >= amount) && (from != into)) {
int newAmountFrom = accounts[from] - amount;
int newAmountTo = accounts[into] + amount;
wastrSomeTime();
accounts[from] = newAmountFrom;
accounts[into] = newAmountTo;
}
label.setText("转账完成:" + count++);
}
public void start() {// 启动程序
stop();
for (int i = 0; i < accounts.length; i++)
customer[i] = new Customer(i, this);
}
private void stop() {// 停止
for (int i = 0; i < accounts.length; i++)
if (customer[i] != null)
customer[i].setFlagValue();
}
private void wastrSomeTime() {// 处于等待休眠中
try {
Thread.sleep(waste_time);
} catch (InterruptedException ie) {
System.out.println(ie);
}
}
private void showAccounts() {// 显示金额
int sum = 0;
for (int i = 0; i < accounts.length; i++) {
sum += accounts[i];
area.append("\n帐户 " + i + ":$" + accounts[i]);
}
area.append("\n总金额:$" + sum);
area.append("\n转账总次数:" + count + "\n");
}
public void actionPerformed(ActionEvent ae) {// 为button组件添别事件监听
if (ae.getSource() == display)
showAccounts();
else if (ae.getSource() == start)
start();
else if (ae.getSource() == stop)
stop();
}
public static void main(String args[]) {
SavingOffice bank = new SavingOffice();
}
}
class Customer extends Thread {// 顾客类
private SavingOffice bank = null;
private int id = -1;
private boolean flag = false;
public Customer(int _id, SavingOffice _bank) {
bank = _bank;
id = _id;
start();
}
public void start() {
flag = true;
super.start();// 启动线程
}
public void setFlagValue() {// 设置为不转账状态
flag = false;
}
public void run() {// 运行该线程
while (flag) {
int into = (int) (SavingOffice.num_accounts * Math.random());
int amount = (int) (1000 * Math.random());
bank.transfer(id, into, amount);
yield();
}
}
}
实例235 门锁打不开了(死锁)
实例236 门锁终于被打开了(解决死锁)
package Chapter17;
public class DoorOpen {
static String[] keys = new String[] { "第1把钥匙", "第2把钥匙" };
static class DoorKey1 extends Thread { // 静态内部类
public void run() {
synchronized (keys[0]) { // 在同一时间只能有一个类访问
System.out.println("我拿起了" + keys[0] + ",在等着朋友用" + keys[1]
+ "开防盗门");
try {
Thread.sleep(100); // 线程休眠
} catch (Exception e) { // 捕获异常
System.out.println("线程休眠出错:" + e.getMessage());
}
synchronized (keys[1]) {
System.out.println("我又拿出来" + keys[1] + "打开了防盗门");
}
}
}
}
static class DoorKey2 extends Thread { // 静态内部类
public void run() {
synchronized (keys[0]) {
System.out.println("\n朋友拿出了" + keys[0] + ",在等待我用" + keys[1]
+ "开防盗门");
try {
Thread.sleep(100); // 线程休眠
} catch (Exception e) { // 捕获异常
System.out.println("线程休眠出错:" + e.getMessage());
}
synchronized (keys[1]) {
System.out.println("朋友又拿出了" + keys[1] + "打开了防盗门");
}
}
}
}
static class GoWrong extends Thread { // 静态守护线程类
public GoWrong() {
this.setDaemon(true); // 线程设置守护
}
public void run() {
while (true) {
try {
Thread.sleep(1000); // 线程休眠
} catch (Exception e) { // 捕获异常
System.out.println("线程休眠出错:" + e.getMessage());
}
System.out.println("守护线程:程序正在运行...");
}
}
}
public static void main(String[] args) { // java程序主入口处
DoorKey1 one = new DoorKey1(); // 实例化对象
DoorKey2 two = new DoorKey2();
GoWrong daemon = new GoWrong();
one.start(); // 启动线程
two.start();
daemon.start();
}
}
实例237 一个死锁的例子
package Chapter17;
import java.awt.*;
import java.awt.event.*;
public class DeadLock extends Frame {
protected static final String[] names = { "One", "Two" };// 创建一个字符串数组,用于存放线程的名字
private int accounts[] = { 1000, 1000 };// 存入账号
// 创建TextArea组件
private TextArea info = new TextArea(5, 40);
private TextArea status = new TextArea(5, 40);
public DeadLock() {// 构造方法
super("致命的死锁!");// 调用父类Frame的带参构造方法
this.setLayout(new GridLayout(2, 1));
add(makePanel(info, "账号"));
add(makePanel(status, "线程"));
validate();
pack();
show();
// 创建DeadLockThread对象
DeadLockThread A = new DeadLockThread(0, this, status);
DeadLockThread B = new DeadLockThread(1, this, status);
this.addWindowListener(new WindowAdapter() {// 添加单击事件监听
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public synchronized void transfer(int from, int into, int amount) {// 转账
info.append("\n帐户 One:$" + accounts[0]);// 将给定文本追加到文本区的当前文本
info.append("\n帐户 Two:$" + accounts[1]);
info.append("\n>=$" + amount + "从" + names[from] + "到" + names[into]);
while (accounts[from] < amount) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
accounts[from] = amount;
accounts[into] = amount;
notify();
}
}
private Panel makePanel(TextArea ta, String title) {// 创建面板,按选择的布局方式将组件进行布局
Panel p = new Panel();
p.setLayout(new BorderLayout());
p.add("North", new Label(title));
p.add("Center", ta);
return p;
}
public static void main(String[] args) {// 本程序的主方法
DeadLock dl = new DeadLock();
}
}
class DeadLockThread extends Thread {// 死锁线程
private DeadLock dl;
private int id;
private TextArea display;
public DeadLockThread(int _id, DeadLock _dl, TextArea _display) {
dl = _dl;
id = _id;
display = _display;
start();
}
public void run() {
while (true) {
int amount = (int) (1500 * Math.random());
display.append("\nThread" + DeadLock.names[id] + "将 $" + amount
+ "存入" + DeadLock.names[(1 - id)]);
try {
sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
dl.transfer(id, 1 - id, amount);
}
}
}