Java程序设计:必实验4 线程应用

本文详细介绍了如何使用Java实现并发编程,包括使用Runnable接口创建线程、同步机制确保线程安全(如数字和月份交替输出、银行账户取款操作)、以及解决桥问题模拟多人过桥场景。
摘要由CSDN通过智能技术生成

(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 + "次!");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值