【深圳大学java程序设计】实验4 线程应用

(1). 运行以下三个程序(要求每个程序运行10次),并对输出结果给出分析。在报告中附上程序截图和详细的文字说明。(15分)

程序1:

程序代码如上,此时都是打印一百次。多次运行代码后大体的结果类似下图,即a和b交替输出后才输出数字。

这是因为,打印字符比打印数字要快得多,因此线程1、2的存在时间很短。

将次数改为1000即可看到三者交替。

程序2:

代码如上,此时都是打印一百次。多次运行代码后大体的结果类似下图,即a和b交替输出后才输出数字。

程序3:

多次运行代码后发现,余额不是1就是2,并不是预期的100。

经过分析是没有处理好同步问题,多个线程拿到同一个变量,写回去后覆盖了。比如可能很多个都拿到余额为1,之后又都将其赋值为2。

解决的方法是要保证每个线程都单独处理余额balance。

在存款操作添加synchronized,保证其是原子操作即可。

如下图所示,再次运行后即为100。

(2). 编写Java应用程序实现如下功能:第一个线程输出数字1,2,..,12,第二个线程输出英文单词数字和月份One January, Two February, …, Twelve December,输出的顺序和格式为1OneJanuary2TwoFebruary...12TwelveDecember,即每1个数字紧跟着2个英文单词的方式。要求线程间实现通信。要求采用实现Runnable接口和Thread类的构造方法的方式创建线程,而不是通过Thread类的子类的方式。在报告中附上程序截图、运行结果截图和详细的文字说明。(15分)

这段代码实现了两个线程分别输出数字和月份,并且要求数字和月份交替输出,即每输出一个数字后,接着输出两个英文单词的月份。以下是代码的主要思路:

共享资源与同步机制:

定义了一个共享的锁对象 lock,用于同步两个线程的操作。

使用 numberPrinted 变量标识数字是否已经打印,以确保数字和月份的交替输出。

数字线程 (NumberPrinter):

实现了 Runnable 接口,用于创建一个线程对象。

在 run 方法中,通过 synchronized (lock) 同步块,确保多个线程访问临界区时的互斥性。

使用 while 循环检查 numberPrinted 的状态,如果数字已经打印,则进入等待状态(lock.wait()),直到被唤醒。

输出数字并设置 numberPrinted 为 true,然后唤醒等待的线程(月份线程)。

月份线程 (MonthPrinter):

同样实现了 Runnable 接口,创建了另一个线程对象。

在 run 方法中,同样使用 synchronized (lock) 同步块,确保对共享资源的访问是同步的。

使用 while 循环检查 numberPrinted 的状态,如果数字未打印,则进入等待状态(lock.wait()),直到被唤醒。

输出月份并设置 numberPrinted 为 false,然后唤醒等待的线程(数字线程)。

主方法 (main):

创建两个线程对象,分别用于输出数字和月份。

启动这两个线程。

同步控制:

通过 synchronized 关键字和 wait()、notify() 方法实现线程之间的同步和通信。

在共享资源被修改时,通过 wait() 让当前线程进入等待状态,而在修改完成后通过 notify() 唤醒等待的线程。

(3). 编写Java应用程序实现如下功能:创建工作线程,模拟银行现金账户取款操作。多个线程同时执行取款操作时,如果不使用同步处理,会造成账户余额混乱,要求使用syncrhonized关键字同步代码块,以保证多个线程同时执行取款操作时,银行现金账户取款的有效和一致。要求采用实现Runnable接口和Thread类的构造方法的方式创建线程,而不是通过Thread类的子类的方式。在报告中附上程序截图、运行结果截图和详细的文字说明。(25分)

BankAccount 类:

BankAccount 类表示银行账户,包含了一个私有成员变量 balance 表示账户余额。

构造方法 public BankAccount(int balance) 用于初始化账户余额。

方法 public synchronized void withdraw(int amount) 为同步方法,用于进行取款操作。在该方法中,通过 synchronized 关键字确保了多个线程对账户的安全访问。

WithdrawThread 类:

WithdrawThread 类实现了 Runnable 接口,表示取款线程。

构造方法 public WithdrawThread(BankAccount account) 接受一个 BankAccount 对象,表示共享的银行账户。

public void run() 方法是实现 Runnable 接口的方法,其中包含了取款的逻辑。通过调用 account.withdraw(amount) 方法进行同步的取款操作。

Third 类(主类):

Third 类包含了 main 方法,是程序的入口。

在 main 方法中,创建了一个初始余额为 500 的银行账户对象 account。

创建两个取款线程 thread1 和 thread2,它们共享同一个银行账户对象。

启动两个线程,它们会并发执行取款操作。

运行过程解释:

每个取款线程会执行 5 次取款操作,每次取款的金额是随机生成的。

在 withdraw 方法中,通过同步机制确保了多个线程对账户的安全访问,避免了余额混乱的问题。

程序的输出中,通过 System.out.println 输出了每次取款的结果,包括取款成功或失败以及余额信息。

(4). 有一座东西向的桥,只能容纳一个人,桥的东边有20个人(记为E1,E2,…,E20)和桥的西边有20个人(记为W1,W2,…,W20),编写Java应用程序让这些人到达对岸,每个人用一个线程表示,桥为共享资源,在过桥的过程中输出谁正在过桥(不同人之间用逗号隔开)。运行10次,分别统计东边和西边的20人先到达对岸的次数。要求采用实现Runnable接口和Thread类的构造方法的方式创建线程,而不是通过Thread类的子类的方式。在报告中附上程序截图、运行结果截图和详细的文字说明。(25分)

代码模拟了一座桥,有东边和西边两侧的人,每个人都是一个线程。这些人需要过桥,但桥只能容纳一个人,因此需要同步控制多个线程的过桥操作。

代码的主要思路:

创建一个 Person 类,实现 Runnable 接口,表示每个过桥的人。

在 Person 类中,通过 synchronized 关键字锁定一个对象(在这里是 lock 对象),以确保同一时刻只有一个人能够通过桥。

在 run() 方法中,通过 synchronized 锁定的代码块,模拟每个人过桥的操作。在过桥时,输出人的名字,并记录最后一个过桥的人是从东边过来的还是从西边过来的。

在主程序中,创建多个东边和西边的人线程,并启动它们。

在 runSimulation() 方法中,通过 joinThreads() 方法等待所有线程执行完成。

输出每次模拟的统计结果,统计东边和西边先过桥的次数。

(by 归忆)

  • 35
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

归忆_AC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值