(1) 编写Java应用程序实现如下功能:第一个线程输出数字1,2,..,12,第二个线程输出英文单词数字和月份One January, Two February, …, Twelve December,输出的顺序和格式为1OneJanuary2TwoFebruary...12TwelveDecember,即每1个数字紧跟着2个英文单词的方式。要求线程间实现通信。要求采用实现Runnable接口和Thread类的构造方法的方式创建线程,而不是通过Thread类的子类的方式。
package 必实验4;
class OutPut{
int timesNum =1;
int timesMon =1;
String []months = {"OneJanuary", "TwoFebruary", "ThreeMarch",
"FourApril", "FiveMay","SixJune", "SevenJuly", "EightAugust",
"NineSeptember", "TenOctober", "ElevenNovember", "TwelveDecember"
};
// 打印数字的方法
synchronized void printNum() {
for (timesNum = 1; timesNum <= 12; timesNum++) {
if (timesNum > timesMon) {//若后面月份还未打印
try {
wait();// 如果数字超过月份,等待通知
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print(timesNum);
notify();// 通知等待中的线程(printMon)继续执行
}
}
// 打印月份的方法
synchronized void printMon() {
int idx = 0;
for (timesMon = 1; timesMon <= 12; timesMon++) {
if (timesNum <= timesMon) {//若前面数字还未打印
try {
wait();// 如果月份超过数字,等待通知
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print(months[idx++]);
notify();// 通知等待中的线程(printNum)继续执行
}
}
}
class printNumber implements Runnable{
OutPut outPut;
// 构造方法用于初始化 OutPut 对象
public printNumber(OutPut o) {
outPut = o;
}
// Run 方法执行在单独的线程中打印数字
public void run(){
outPut.printNum();
}
}
class printMonth implements Runnable{
OutPut outPut;
// 构造方法用于初始化 OutPut 对象
public printMonth(OutPut o) {
outPut = o;
}
// Run 方法执行在单独的线程中打印月份
public void run(){
outPut.printMon();
}
}
public class task2 {
public static void main(String[] args) {
OutPut outPut=new OutPut();// 创建一个共享对象以进行通信
// 创建打印数字的线程
Thread thread1=new Thread(new printNumber(outPut));
// 创建打印月份的线程
Thread thread2=new Thread(new printMonth(outPut));
// 启动打印数字的线程
thread1.start();
// 启动打印月份的线程
thread2.start();
}
}
(2)编写Java应用程序实现如下功能:创建工作线程,模拟银行现金账户取款操作。多个线程同时执行取款操作时,如果不使用同步处理,会造成账户余额混乱,要求使用syncrhonized关键字同步代码块,以保证多个线程同时执行取款操作时,银行现金账户取款的有效和一致。要求采用实现Runnable接口和Thread类的构造方法的方式创建线程,而不是通过Thread类的子类的方式。
package 必实验4;
import java.util.Scanner;
class bankAccount{
private int balance;
// 构造方法,用于初始化账户余额
public bankAccount(int b) {
balance = b;
}
// 获取余额的方法
public int getBalance() {
return balance;
}
// 同步方法,用于取款
public synchronized void withdraw(int amount) {
if(amount>0 && amount<=balance) {//余额足够,可以取款
try {
Thread.sleep(100);// 模拟取款过程中的延迟
}
catch(InterruptedException e) {
e.printStackTrace();
}
balance -= amount;
System.out.println(Thread.currentThread().getName()
+"取出:"+amount+"\n剩下的余额:"+balance);
}
else {//余额不足,无法取款
System.out.println(Thread.currentThread().getName()
+"无法取出"+amount+"因为余额不足");
}
}
}
class withdrawTask implements Runnable{
private bankAccount account;
private int amount;
// 构造方法,用于初始化取款任务
public withdrawTask(bankAccount a,int m) {
account = a;
amount = m;
}
// 实现 Runnable 接口的 run 方法
@Override
public void run() {
account.withdraw(amount);
}
}
public class task3 {
public static void main(String[] args) {
Scanner reader = new Scanner(System.in);
//假设有四个账户,且初始余额都为1000
bankAccount account1 = new bankAccount(1000);
bankAccount account2 = new bankAccount(1000);
bankAccount account3 = new bankAccount(1000);
bankAccount account4 = new bankAccount(1000);
System.out.println("你好,顾客1,请输入你要取款的金额:");
int x1 = reader.nextInt();
System.out.println("你好,顾客2,请输入你要取款的金额:");
int x2 = reader.nextInt();
System.out.println("你好,顾客3,请输入你要取款的金额:");
int x3 = reader.nextInt();
System.out.println("你好,顾客4,请输入你要取款的金额:");
int x4 = reader.nextInt();
// 创建四个取款任务
Runnable withdrawTask1 = new withdrawTask(account1, x1);
Runnable withdrawTask2 = new withdrawTask(account2, x2);
Runnable withdrawTask3 = new withdrawTask(account3, x3);
Runnable withdrawTask4 = new withdrawTask(account4, x4);
// 创建四个线程,分别执行取款任务
Thread thread1 = new Thread(withdrawTask1,"顾客1");
Thread thread2 = new Thread(withdrawTask2,"顾客2");
Thread thread3 = new Thread(withdrawTask3,"顾客3");
Thread thread4 = new Thread(withdrawTask4,"顾客4");
// 启动四个线程,同时执行取款任务
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
(3)有一座东西向的桥,只能容纳一个人,桥的东边有20个人(记为E1,E2,…,E20)和桥的西边有20个人(记为W1,W2,…,W20),编写Java应用程序让这些人到达对岸,每个人用一个线程表示,桥为共享资源,在过桥的过程中输出谁正在过桥(不同人之间用逗号隔开)。运行10次,分别统计东边和西边的20人先到达对岸的次数。要求采用实现Runnable接口和Thread类的构造方法的方式创建线程,而不是通过Thread类的子类的方式。
package 必实验4;
import java.util.concurrent.ThreadLocalRandom;
class Bridge {
//判断桥是否在使用
private boolean inUse = false;
//过桥方法
public synchronized void crossBridge(String person) {
while (inUse) {
try {
wait();//如果在用则要等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//inUse==0即没有人使用桥,桥可以用了
System.out.print(person + "正在过桥,");
try {
Thread.sleep(100);//过桥中,其它线程不运行
} catch (InterruptedException e) {
e.printStackTrace();
}
//System.out.print(person + "过完桥。");
inUse = true;
notifyAll();
}
public synchronized void releaseBridge() {
inUse = false;//桥不用了,释放
notifyAll();
}
}
class Person implements Runnable {
private String name;
private Bridge bridge;
//构造方法
public Person(String n, Bridge b) {
name = n;
bridge = b;
}
//重写run方法
@Override
public void run() {
try {
//随机生成一个人的序号,在1到21中(最后21不包含)
int personNumber = ThreadLocalRandom.current().nextInt(1, 21);
String person = name + personNumber;
bridge.crossBridge(person);
Thread.sleep(50);//过桥时间
bridge.releaseBridge();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class task4 {
public static void main(String[] args) {
int eastCounter = 0;
int westCounter = 0;
//运行10轮过桥
for (int i = 1; i <= 10; i++) {
Bridge bridge = new Bridge();
//东边20个人即20个东线程
Thread[] eastThreads = new Thread[20];
for (int j = 0; j < 20; j++) {
Person person = new Person("E", bridge);
eastThreads[j] = new Thread(person);
}
//西边20个人即20个西线程
Thread[] westThreads = new Thread[20];
for (int j = 0; j < 20; j++) {
Person person = new Person("W", bridge);
westThreads[j] = new Thread(person);
}
System.out.println("\n第 " + i + " 轮过桥开始:\n");
//启动所有线程
for (int j = 0; j < 20; j++) {
eastThreads[j].start();
westThreads[j].start();
}
try {
//等待所有线程执行完毕
for (int j = 0; j < 20; j++) {
eastThreads[j].join();
westThreads[j].join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
//检查是否有一边的所有人都过完桥
boolean eastSideCrossed = true;
boolean westSideCrossed = true;
for (int j = 0; j < 20; j++) {
if (eastThreads[j].isAlive()) {
eastSideCrossed = false;
break;
}
if (westThreads[j].isAlive()) {
westSideCrossed = false;
break;
}
}
//更新两边的计数器,若20人都过完输出提示信息
if (eastSideCrossed) {
eastCounter++;
System.out.println("东边20人过完桥啦!");
}
if (westSideCrossed) {
westCounter++;
System.out.println("西边20人过完桥啦!");
}
}
System.out.println("\n最后过完桥次数:");
System.out.println("东边20人过完" + eastCounter + "次!");
System.out.println("西边20人过完" + westCounter + "次!");
}
}