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

  • 12
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 多线程中的同步访问是指多个线程同时访问共享资源时,需要通过一定的机制来保证数据的正确性和一致性。常见的同步访问机制包括锁、信号量、条件变量等。在Java中,可以使用synchronized关键字来实现同步访问,也可以使用Lock接口及其实现类来实现。同步访问的目的是避免多个线程同时修改同一个共享资源,从而导致数据不一致或者程序出现异常。 ### 回答2: 多线程是一种被广泛应用的编程技术,其可以使用多个线程同时执行不同的任务,以提高程序的运行效率和响应速度。但同时使用多个线程也会带来一些问题,其中之一就是线程之间的同步访问问题。本文将从同步访问的概念、线程安全、同步方式等方面介绍多线程的同步访问问题。 一、同步访问的概念 多线程中的同步访问是指多个线程在访问共享资源时,为了避免竞争条件和数据不一致问题,需要进行协调和同步。例如,多个线程同时访问同一个对象中的方法或属性,就需要进行同步处理,避免出现数据不一致或错乱的情况。 二、线程安全 线程安全是指在多线程环境中,一个对象能够保证经过多个线访问后仍能保持其状态和正确性。线程安全的实现需要考虑以下两个方面: 1、互斥访问:互斥访问指的是,在某个线访问对象时,其他线程不能同时访问该对象,需要进行排队等待。 2、共享对象的状态安全:共享对象的状态安全指的是,共享对象在多个线程中被访问时,能够保持其状态的一致性,避免出现数据不一致或错乱的情况。 三、同步方式 实现多线程的同步访问可以使用以下方式: 1、同步方法:将需要同步访问的代码块封装在一个 synchronized 修饰的方法中,保证在任意时刻最多只有一个线程执行该代码块。但是需要注意,同步方法会影响程序的执行效率,因为其他线程必须等待当前线程执行完毕后才能执行。 2、同步块:使用 synchronized 关键字和任意对象实现同步块。同步块将需要同步访问的代码块括到 synchronized 关键字指定的对象中,保证在任意时刻最多只有一个线程执行该代码块。与同步方法相比,同步块的粒度更细,执行效率也更高。 3、Lock 锁:Lock 锁是 java.util.concurrent.locks 包中提供的一种线程锁,通过 Lock 的 lock() 和 unlock() 方法实现同步访问。与 synchronized 关键字相比,Lock 锁具有更灵活、更可靠的特性,如可重入、可中断、timeout 等。但是需要注意,使用 Lock 锁时必须手动释放锁,否则会导致死锁等问题。 四、总结 多线程的同步访问是提高程序运行效率和响应速度的必要手段,同时也是保障程序正确性和安全性的重要措施。在实现多线程的同步访问时,需要考虑互斥访问和共享对象的状态安全问题,并选择合适的同步方式,如同步方法、同步块和 Lock 锁等。通过合理的同步处理,可以避免出现数据不一致或错乱的情况,提高程序的稳定性和可靠性。 ### 回答3: 在Java编程中,多线程是一项非常重要的概念。Java提供了各种各样的线程操作,可以使程序员更自由地控制线程的执行。在使用多线程的过程中,同步访问是一项非常核心的技术,它能够帮助程序员解决线程并发访问时可能引发的各种问题。 多线程可能涉及到多个线程对同一资源的操作,例如内存或是磁盘文件。如果多个线程同时访问同一个资源,就可能导致数据的不一致性、竞争条件和死锁等问题。解决这类问题的一种方法就是同步访问同步访问的原理是在多个线程使用同一个资源的时候,使用锁机制来保证各个线程对资源的访问顺序,确保数据一致性。Java中提供了关键字synchronized来实现同步访问,这个关键字可以应用于方法和代码块。 通过使用synchronized,我们可以使多个线程在访问同一对象时有序地执行,从而避免竞争条件的产生。在使用synchronized时,要注意一些细节,例如避免死锁,确保锁的粒度正确等。 另外,Java的并发包中提供了各种各样的同步访问机制,例如ReentrantLock、Semaphore、CountDownLatch等等。这些机制可以更加灵活地控制线程的访问,使多线程编程更加方便和安全。 总之,同步访问是多线程编程中非常重要的一个概念。通过使用同步访问,我们可以保证多个线程对同一资源的访问有序地进行,从而避免竞争条件和死锁等问题。在Java中,我们可以使用synchronized关键字或是并发包中的各种机制来实现同步访问

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

驼同学.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值