Java语言:多线程之线程同步和线程间通信(银行存取款问题)

目录

线程同步

线程间通信


线程同步

线程同步问题,重点是同步这两个字

在多线程的运行中,存在这样一些问题

1、各个线程通过竞争,从而获得CPU的时间片,获得时间片的机会是随机的

2、各个线程在运行的时候,到底会占用多久的时间片,也是未知的,意思就是说

,你有可能整个线程并没有执行完,会被其他的线程插一脚,这样非常有可能导致数据的不一致

 

下面举一个例子

这个例子讲的是银行存取款问题,这是一个经典问题(我只是简单的讲一下这个问题

,如果记得没错的话,这部分的知识,是操作系统的知识)

银行存取款问题就是一个公司只有一个账户,然后多人对其进行操作,有可能会有同时操作的可能

直接上代码吧!

bank类

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

存款方法

在存款和取款方法中分别加入了sleep方法

这里是为了模拟线程在执行中进入阻塞状态

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

取款方法

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

 

存款线程类

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

 

取款线程类

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

 

测试类

这里加上了join方法的原因是

想要bank对象能够在最后打印

因为在哪个方法中调用线程,哪个方法就会被挂起来

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

 

为什么会出现上面的问题呢?

我的分析如下

可能在save对象开始操作的时候,操作完balance之后,balance值为1100

,没有调用setBalance方法将数据及时存取,却被打断

然后draw对象开始操作,draw对象操作完balance之后,balance值为800

,但是此时线程又被打断

save对象操作的线程继续执行,调用setBalance方法,将值1100写进balance中

然后draw对象操作的线程就开始操作,调用setBalance方法,将值800写进线程中

这样最后balance的值就是800

但是因为两个存取款方法都有输入输出,所有输入输出的结果不一样

 

出现上面这个问题最大的问题就是线程在执行的过程中被中断,进入阻塞状态

所以只要解决这个问题即可

 

所以引入了synchronized关键字

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

synchronized可以确保共享对象在同一时刻只能被一个线程访问

下面是synchronized的使用方法,如下图所示

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

语句块中的obj是要执行同步的对象

将存取款方法改了一下,如下图

取款方法

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

取款方法

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

改完之后,运行结果如下

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

 

线程间通信

银行存取款问题描述如下

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

下面这张图将银行的存取款问题用消费者、生产者和一个中间存储介质代替

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

银行存取款问题的中心思想就是生产一个消费一个

生产者类

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

消费者类

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

Queue类

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

测试类

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

运行结果

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

这里你会发现一个问题,就是会出现连续的生产,或者是连续的消费,如上图

所以这里要设置一个标志,告诉消费者,里面有钱才可以消费,告诉生产者,里面有钱就不需要生产

因此

这里设置一个flag

如果flag是true

那么就可以让消费者进行消费

如果flag为flase

那么说明还没有生产,就不可以消费

那么你的消费的方法需要等待

同理当flag为true的时候

生产者也不可以继续生产

也要进入等待

 

等待由wait方法执行

等待其实是阻塞的状态

当消费者在等待,生产者也在等待

那么就会陷入死锁的状态

因此要进行唤醒

这里就要提到几个方法,如下

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

对消费者和生产者类中的run方法进行修改如下,加上flag和唤醒方法

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

生产者和消费者类还要加上wait方法,用于等待,这样既可

运行结果如下

Java语言:多线程之线程同步和线程间通信(银行存取款问题)

 

对于这个问题主要就是有两个点

第一个是死锁的问题,因为使用到了wait方法,所以要使用notifyAll方法唤醒所有的线程

第二个问题是让其生产一次消费一次的问题,这里就要用到一个标志符flag

第三个问题就是同步的问题,因为如果不写同步,可能会连续生产10个,再消费一个

也有可能还没有生产就开始消费,这里可以使用synchronized关键字解决这个问题

 

自己还是觉得这篇文章没有讲清楚,自己有时间会再改进的