多线程:线程安全与同步

线程安全问题

线程安全问题产生的三个必要条件

  • 多线程环境中
  • 有共享数据(成员变量,而非局部变量,栈中是线程独立的)
  • 多个线程操作(增删改)了共享数据

【单线程】以及【多线程在没有访问共享数据的情况下】是不会产生线程安全问题的:

一旦多线程访问了共享数据,就有可能产生安全问题:

我的理解:这里卖了重复的票以及出现了不存在的票,表明程序出现了安全问题,产生混乱。代码实现如下:

创建三个Thread对象共享这100张票:

此时,结果就会出现重复的票以及错误的票:

原理图解如下:

注意:线程安全问题是需要避免的,我们可以让一个线程在访问共享数据的时候,无论其是否失去了cpu的执行权,其它的线程只能等待当前线程卖完票,才能继续进行卖票。保证一次只有一个线程在执行。


线程同步技术

线程同步技术用于解决线程安全的问题。原理如下:

类似于,你前一个来执行任务的把锁都拿走了,我后面的一个人打不开门,只有前一个人任务完成归还锁,后面一个人才能进去。

注意:因为这一过程会频繁地判断锁、获取锁、归还锁,所以程序效率会有所降低,但是也保证了线程的安全性,利大于弊。

线程同步技术能够保证各线程之间是互斥的,即不会出现交叉执行的情况。

具体实现

1、同步代码块

格式如下:

注意事项:

  • 同步代码块中的锁对象可以是任意的对象(也就是说随便创建一个对象都能放进去)
  • 但是必须保证多个线程使用的锁对象是同一个
  • 锁对象的创建最好在run方法外进行

锁对象的作用就是:把同步代码块锁住,一次只让一个线程在同步代码块中执行

怎么判断哪些是可能会出现线程安全问题的代码呢?目前就以从哪里开始使用了共享数据,到哪结束使用的这一段为准。示例如下:

2、同步方法

就是把访问了共享数据的代码放到一个方法中,然后在run方法中再调用这个方法即可。

同步方法格式如下:

示例如下:

注意:此谁充当了锁对象呢?就是this,即实现类对象,所以不用额外创建锁对象。也就是说同一个类中所有的同步方法都共用一个锁对象。

反过来,如果多个方法需要使用同一个锁对象,最好放在同一个类中,实现了代码的高内聚,提高代码的健壮性。

同步方法也可以使用静态的(了解一下):

这时的锁对象就只能通过类来产生:本类的class属性,即class文件对象。

因此静态方法使用的锁对象是所在类的字节码文件对象。

发布了70 篇原创文章 · 获赞 1 · 访问量 2277

猜你喜欢

转载自blog.csdn.net/caozp913/article/details/103450246