美文网首页程序员Java
2019-09-30关于多线程共享资源的几个安全性问题

2019-09-30关于多线程共享资源的几个安全性问题

作者: 一个小素 | 来源:发表于2019-09-30 11:48 被阅读0次

多线程编程需要考虑最多的问题就是线程安全问题,线程安全指的就是共享资源的同步问题。所谓同步就是指多个线程在同一个时间段内只能由一个线程进行操作,其他线程需要等待正在操作的线程完成操作之后才可以继续执行。

1深入了解Thread类和Runnable接口

通过继承Thread类和实现Runnable接口都可以实现多线程的创建,那么两者有哪些联系和区别呢?

01、Thread类的定义

以下代码片段,摘自JDK源码里Thread类的部分定义:

public class Thread implements Runnable {

通过以上Thread类的定义,可以看出,Thread类是Runnable接口的子类,但在Thread类中并没有完全地实现Runnable接口中的run方法。Thread类中的run方法调用的是target的run方法,而target则是Runnable接口的子类,所以通过继承Thread类实现多线程,则该线程子类必须覆写run方法。

02、通过实现Runnable接口创建多线程的UML图

通过以上的UML类图,我们可以发现,Thread类和MyThread类都实现了Runnable接口,通过实现Runnable接口来创建线程类MyThread,其实就是把MyThread类放到了Thread类的target变量中,线程启动后,实际上是调用的target的run方法,也就是MyThread类中的run方法,所以说MyThread类必须覆写run方法。这种操作模式是典型的代理设计模式。

通过以上2个部分的说明,我们可以很明显地看出Thread类和Runnable接口的联系,那就是Thread类实现了Runnable接口。

03、通过继承Thread类实现的多线程能实现资源共享吗

答案是不能,如果一个类继承Thread类的话,它就不适合多个线程之间共享资源。

示例:通过继承Thread类的方式实现模拟售票场景,假设有5张电影票,两个窗口同时卖这5张电影票。

public class SaleTicketTask extends Thread {

从以上的程序运行结果来看,通过继承Thread类实现的多线程,每一个窗口都卖了5张电影票,没有达到5张电影票资源共享的目的。

04、通过实现Runnable接口创建的多线程可以实现资源共享

如果一个类继承Thread类的话,它就不适合多个线程之间共享资源,但是一个类实现了Runnable接口的话,就可以方便的实现资源共享。

示例:通过实现Runnable接口的方式实现模拟售票场景,假设有5张电影票,两个窗口同时卖这5张电影票。

public class SaleTicketTask1 implements Runnable {

从以上的运行结果来看,通过实现Runnable接口实现的多线程,两个窗口共卖了5张电影票,达到了5张电影票资源共享的目的。

实现Runnable接口相对于继承Thread类来说,有以下3个优势:

  1. 适合多个相同程序代码的线程去处理同一资源的情况;
  2. 可以避免由于Java的单继承特性带来的局限;
  3. 代码能够被多个线程共享,代码与数据可以独立;

因此,在开发中建议通过实现Runnable接口来创建多线程。

2演示线程安全问题

上面通过实现Runnable接口实现的线程,达到了两个窗口卖出5张电影票的目的,那么请大家思考,以上的程序是线程安全的吗?

答案是以上的程序不是线程安全的,可能出现重复售票的情况。

01、演示共享资源的线程不安全问题

我们可以在上面的SaleTicketTask1类中的run方法中加入一段线程休眠的代码,来放大这种线程不安全性,再次观察程序的运行情况。

public class SaleTicketTask1 implements Runnable {

通过上面两次程序的运行结果很明显的可以看出,两个线程窗口售票出现了共享资源(5张电影票)不安全的情况,第一次的程序卖出了3张重复票,第二次的程序票已近卖完了,依然又卖出了一张票号为0的票。

3解决线程安全问题

在多线程编程中,遇到多个线程要操作同一个资源的时候,就有可能出现共享资源的同步问题。要想解决这样的问题,就必须使用同步。

所谓同步就是指多个线程在同一个时间段内只能由一个线程进行操作,其他线程需要等待正在操作的线程完成操作之后才可以继续执行。

在Java编程中,实现同步操作的关键字是synchronized,解决资源共享的同步操有两种方法:一是使用同步代码块,二是使用同步方法。

01、使用同步代码块解决共享资源的线程不安全问题

代码块就是指用“{}”括起来的一段代码,如果再代码块上加上synchronized关键字,则此代码块就是同步代码块。

同步代码块的格式如下:

synchronized ( 同步对象 ){

在使用同步代码块时必须指定一个同步对象,一般将当前对象(this)设置成同步对象。

示例1:使用同步代码块解决以上售票的同步问题

public class SaleTicketTask1 implements Runnable {

通过上面的结果可以看出,加入同步代码块确实解决了共享资源电影票安全性的问题,但是上面的示例代码,在run方法开始的时候就加入了synchronized同步,导致只有一个窗口在卖票,因此以上的代码是不完美的。

示例2:使用同步代码块解决以上售票的同步问题

public class SaleTicketTask1 implements Runnable {

说明,上面的程序通过同步代码块,完成了共享资源的同步安全性问题。

02、使用****同步方法****解决共享资源的线程不安全问题

同步方法顾名思义就是在方法的声明的时候加上synchronized关键字。

Java中方法定义的完整格式如下:

访问权限{public|default|protected|private} [final] [static] 

示例:使用同步方法解决以上售票的同步问题

public class SaleTicketTask2 implements Runnable {

说明,上面的程序通过同步方法,也能完成共享资源的同步安全性问题。

以上内容对多线程的两种实现方式的联系和区别、对多线程编程中共享资源同步问题的解决进行了说明,希望大家可以熟练掌握。

相关文章

  • 2019-09-30关于多线程共享资源的几个安全性问题

    多线程编程需要考虑最多的问题就是线程安全问题,线程安全指的就是共享资源的同步问题。所谓同步就是指多个线程在同一个时...

  • 02.线程安全性问题

    [TOC] 安全性问题概述 什么是安全性问题 多线程情况下的安全问题,是指数据的一致性问题,在多线程环境下,多个线...

  • IOS多线程安全(线程锁)

    线程安全 线程的不安全是由于多线程访问和修改共享资源而引起的不可预测的结果。ios多线程开发中为保证线程的安全常用...

  • 多线程安全性和Java中的锁

    Java是天生的并发语言。多线程在带来更高效率的同时,又带来了数据安全性问题。一般我们将多线程的数据安全性问题分为...

  • ios线程安全

    1.单线程,任务依次串行执行是不存在线程安全问题的。2.多线程访问共享资源而不去修改共享资源也可以保证线程安全 苹...

  • 对 atomic 不能保证线程安全的理解

    先说说什么是线程不安全? 由多线程访问和修改共享资源造成的不可预测的结果叫做线程不安全。 如何避免线程不安全? 通...

  • ThreadLocal实现原理揭秘

    ThreadLocal是什么?对java多线程有了解的人都清楚,在多个线程程序中,会出现线程安全性问题,即多线程是...

  • 线程安全和共享资源

    什么是线程安全可以被多线程同时执行的代码叫做线程安全的代码 共享资源局部变量局部对象的引用对象成员 所以,了解到某...

  • 并发编程专题-04共享模型-无锁(乐观锁)

    1. 无锁和有锁解决线程安全问题 1.1 非线程安全实现 在多线程的环境下,对共享资源的访问存在线程安全问题 1....

  • 第三篇 Java并发编程之线程安全

    一、什么是线程安全 当我们在聊线程安全的时候,其实是在说,在多线程的情况下,多个线程对“共享资源”的访问(读写操作...

网友评论

    本文标题:2019-09-30关于多线程共享资源的几个安全性问题

    本文链接:https://www.haomeiwen.com/subject/uvvcpctx.html