6-6 jmu-Java-07多线程-同步访问 (10 分)

6-6 jmu-Java-07多线程-同步访问 (10 分)

现已有Account类,拥有
属性:
private int balance
方法:
相应的getter方法。

要求为该类编写:

void deposit(int money) //存钱,在余额的基础上加上money
void withdraw(int money) //取钱,在余额的基础上减去money

注意:

  1. 取钱时如果balance<0的时候,会抛出异常。在多线程情况下,如只有一个存钱的线程,但是有多个取钱的线程,很可能会抛出异常。
  2. 需要编写完整的deposit方法与withdraw的前半部分代码解决该问题。

裁判测试程序:

import java.util.Scanner;

//这里是已有的Account类前半部分的代码
/*这里是deposit代码*/
/*这里是withdraw代码的前半部分*/
    if(balance<0) //这里是withdraw代码的后半部分。
        throw new IllegalStateException(balance+"");    
    }

/*系统已有代码,无需关注*/

输入样例:

分别为初始余额、存钱次数、存钱金额
取钱次数、取钱金额。有3个线程。

0 100000 12
100000 4

输出样例:

余额:使用线程跑出的结果。
余额:存钱次数存钱金额 - 取钱次数取钱金额*3

0
0

我的实现代码:

public void deposit(int money) {
		synchronized (this) {
			balance += money;
			notifyAll();
		}
	}

	public void withdraw(int money) {
		synchronized (this) {
			while (balance < money) {
				try {
					wait();
				} catch (InterruptedException e) {
				}
			}
			balance -= money;
			//notifyAll();
		}

题意分析:

本题是典型的生产者消费者问题,涉及到同步访问和线程交互的问题。

  • 本题应有如下要求:
  1. 在同一时刻,只能执行取钱或者存钱操作中的任何一个,不允许同时取钱和存钱。
  2. 不允许超额取钱,必须在余额的数量比所要取用的钱的数量更大的情况下才允许取钱。
  3. 当余额的数量比所要取用的钱的数量更小的时候,当前的取钱的这条线程应该暂时暂停下来。
  4. 由于无法确定究竟什么时候余额超过所需要取钱的数额,所以干脆没存入一次钱就都通知所有的取钱队列开始准备进入可以取钱的流程,而至于能顺利取到钱还是得继续等待,就交给要求2去判断就行。

** 总结相关的知识要点。**

synchronized修饰词可以修饰的对象有三类:

  • 第一类是修饰类内的非静态方法,这种条件下,作用的范围是该类的一个实例,效果是同一时间,该对象的那个实例的所有同步方法,一次只能有一个方法被使用。
  • 第二类是修饰类内的非静态方法的一部分语句,就如同本题的效果,这样做的话,同步限制的范围会更为精确,程序的运行效率会更高。
  • 第三类是修饰类内的静态方法,这种情况作用范围会扩大到这个类的所有实例中,在同一时间内,仅能有一个实例的一个同步方法被访问。

wait()、notify() and notifyAll().

这三个语句实现线程之间的相互交流。

wait()
  1. 使得当前的线程进入等待的序列,直到它被其他的线程用notify()或者notifyAll()唤醒,它被用来让线程等待某一个条件
  2. 它必须在同步区域内部被使用。
  3. 始终应该使用wait循环模式来调用wait方法,永远不要在循环之外调用wait方法循环会在等待之前和之后测试条件
    • 在等待之前测试条件,当条件已经成立时立即就跳过等待,这对确保活性时必要的。
    • 在等待之后测试条件,如果条件不成立的话继续等待,这对于确保安全性时必要的。
    • 在等待之后依然需要不断地监视所等待的条件是否成立,这是等待需要使用循环语句的一个最关键的原因。
  4. 使用wait()语句的一般格式:
public void method(参数) {
		synchronized (this) {
			while ( !condition(条件不满足的时候)) {
					wait();
					}
			}
notify()
  1. 唤醒一个在当前的对象上等待的线程,如果有多个线程在当前的对象上等待,那就任意选择其中的一个来唤醒。
  2. 应该指出的是,调用notify()实际上并没有放弃对资源上的锁。它告诉等待线程可以唤醒。然而,如果对某一资源调用notify(),但同步块内的资源的执行还需要进行10秒,那么线程需要等待额外的10秒,对象上的锁被释放,被唤醒的线程才能执行。
notifyAll()
  1. 唤醒所有在当前对象上等待的线程。
  2. 这并不会影响程序的正确型,因为它可以让条件已经满足的线程往下运行,而对于暂时条件还不满足的线程,他们本身的wait循环结构会让他们继续等待,直到条件被满足。

参考资料

如何使用wait(), notify() and notifyAll() – Java

### 回答1: 您好!如果我理解正确的话,您的问题是关于JMU Java 07多线程同步访问的。以下是我的回答: 多线程编程是指在一个程序中同时执行多个线程的编程技术。多线程编程在提高程序性能、增强程序交互性等方面有很大的优势,但也会引入一些问题,比如线程安全问题。 当多个线程同时访问共享资源时,可能会出现线程不安全的问题,比如数据竞争、死锁等。为了避免这些问题,我们需要使用同步机制来确保线程安全。 Java中提供了多种同步机制,比如synchronized关键字、ReentrantLock类、Semaphore类等。这些同步机制都可以用来保证多线程访问共享资源的安全性。 其中,synchronized是最常用的同步机制之一。在Java中,synchronized关键字可以用来修饰方法或代码块,以实现同步访问共享资源。synchronized可以保证在同一时间只有一个线程可以访问共享资源,从而避免了数据竞争等线程安全问题。 除了synchronized之外,Java还提供了一些其他的同步机制,比如ReentrantLock类和Semaphore类。ReentrantLock类提供了比synchronized更灵活的锁机制,可以实现可重入锁、公平锁等功能。Semaphore类可以控制同时访问共享资源的线程数量,从而避免资源被过度占用的问题。 总的来说,多线程编程是一项复杂而重要的技术,需要仔细研究和实践。在实际开发中,我们需要根据具体的需求选择合适的同步机制来确保多线程访问共享资源的安全性。 ### 回答2: 多线程编程是在当前计算机领域中最为常见的技术之一,它可以利用计算机中的多核处理器来使程序运行更加高效。但是,多线程编程中可能会出现的最大问题就是线程安全,因为线程之间可能会访问相同的资源,从而导致竞态条件。 在Java中,可以通过使用synchronized关键字来实现同步访问,从而避免线程安全问题。synchronized关键字可以用于两种不同的情形:同步方法和同步块。在同步方法中,方法是同步的,即每个线程在执行该方法时都需要获取该对象的锁,如果该锁已经被其他线程获取,则需要等待直到此锁被释放。在同步块中,需要手动指定锁,即每个线程在执行同步块时需要获取该指定锁,其他线程如果需要访问该代码块中的共享资源也需要获取该指定锁,这样就保证了该代码块中的所有共享资源的同步访问。 除了synchronized关键字外,Java还提供了其他一些同步机制来实现线程安全,如ReentrantLock类和CountDownLatch类等。ReentrantLock类可以实现更为灵活的同步访问控制,但需要手动释放锁;而CountDownLatch类则用于同步一个或多个线程,使这些线程在某个条件满足之前一直处于等待状态。 在进行多线程编程时,应该尽量避免对同步访问造成瓶颈,应该通过减小同步代码块的范围等方式来提高程序的效率。此外,多线程编程时还应该进行线程安全性的测试,以确保程序能够正确地运行。 ### 回答3: 在Java中,多线程是一种非常常见的编程方式。由于多线程的特点,对共享资源的访问会出现竞争的情况,这种竞争可能会导致数据不一致或程序异常等问题。因此,在多线程编程中,我们需要采取一些措施来保证共享资源的访问能够正确、有序地进行,这就是同步机制。 同步机制包括两种方式:锁和信号量。锁是最基本的同步机制。锁有两种类型:互斥锁(Mutex)和读写锁(ReadWriteLock)。互斥锁用于保护共享资源,保证同一时间只有一个线程可以访问它,其他线程需要等待锁释放后才能继续访问。读写锁用于读写离场景,提高了多线程访问共享资源的并发性。读写锁支持多个线程同时读取共享资源,但只允许一个线程写入共享资源。 信号量是一种更加高级的同步机制。信号量可以用来控制并发线程数和限制访问共享资源的最大数量。在Java中,Semaphore类提供了信号量的实现。Semaphore可以控制的线程数量可以是任意的,线程可以一起执行,也可以批执行。 除了锁和信号量,Java还提供了一些其他同步机制,比如阻塞队列、Condition等。阻塞队列是一种特殊的队列,它支持线程在插入或者删除元素时阻塞等待。Condition是一种锁的增强,它可以让线程在某个特定条件下等待或者唤醒。 在多线程编程中,使用同步机制需要注意以下几点。首先,同步机制要尽可能的保证资源访问的公平性,避免因为某些线程执行时间过长导致其他线程等待时间过长。其次,同步机制要尽可能的避免死锁的发生,尤其要注意线程之间的依赖关系。最后,同步机制的实现要尽可能地简单,避免过于复杂的代码实现带来的维护成本。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

驼同学.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值