• JVM线程安全


    一、线程的调度方式

      线程调度分为两种方式: 协同式调度和抢占式调度。
    协同式调度:线程的执行时间由线程本身控制,线程将工作执行完之后,通知操作系统切换到其他线程上。缺点:时间不可控,就算出问题,也不会通知操作系统切换,容易阻塞。
    抢占式调度:每个线程由操作系统来分配执行时间,调度。java的线程就是基于抢占式实现的。
    通过线程优先级来控制执行时间。

    二、线程的状态

    (1)新建:创建后,未启动的线程。
    (2)运行:此状态的线程,可能在执行,也有可能是在等待操作系统分配资源。
    (3)无限期等待:不分配cpu时间,等待被唤醒。
    (4)限期等待:不会分配cpu时间,不过无需等待其他线程唤醒,会自动唤醒。
    (5)阻塞:等待资源。
    (6)等待:等待唤醒。
    (7)结束:已终止的线程。

    三、线程安全

      当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行其他任何协调操作,调用这个对象的行为都可以获取正确的结果,则这个对象是线程安全的。

    java各种操作共享的数据分为以下5类:
    (1)不可变
    在java中,不可变的对象都是线程安全的。final修饰的对象,都是线程安全的。
    (2)绝对线程安全
    java中,标榜自己是线程安全的,往往都不是绝对线程安全的。
    如Vector ,虽然add、get等方法都是用synchronized修饰,但并不是绝对线程安全带 。
    (3)相对线程安全
    保证对对象单独操作,是线程安全的。如Vector。
    (4)线程兼容
    线程兼容是指对象本身不是线程安全的,但是可以通过在调用端正确地使用同步手段来保证对象在并发环境中可以安全的使用。
    (5)线程对立
    线程对立是指无论调用端采取了何种措施,都无法在多线程环境中并发使用的代码。

    3.1 synchronized

    synchronized经过编译之后,是在同步块前后分别加上monitorenter和monitorexit这两个字节码指令。

    (1)修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。相当于synchronized(A.class)
    (2)修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
    (3)修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象。锁的是this。也就是当前的对象。
    (4)修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象。锁的是Class对象,也就是A.class.相当于全局锁,线程在该类中所有操作不能进行。

    3.2 ReentrantLock

    (1)等待可中断:
      指拥有锁的线程长期不释放锁,正在等待的线程可以放弃等待。
    (2)公平锁:
      公平锁是指多个线程在等待同一个锁时,需要按照申请锁的时间顺序来获取到锁。
      非公平锁是指多个线程在等待同一个锁时,获取到锁的概率是相同的。
      ReentrantLock默认是非公平锁,但是可以构造出公平锁。

    3.3 可重入代码

      可以在代码执行的任意时刻中断它,转而去执行其他代码,在得到控制权之后,原来的程序不会出现任何错误,这个代码就为可重入代码。
    可重入代码是线程安全的。

    3.4 ThreadLocal 

      如果一段代码中所需要的数据必须与其他代码共享,那么最好将这些代码放在同一个线程中执行。这样,我们可以用ThreadLocal来实现数据在同一个线程中共享,而不会出现数据争用。
      每个线程对象中,都有一个ThreadLocalMap对象,用来存放线程本地变量,变量只线程中的代码可见。其中最经典的一个应用就是,一个web端请求,对应一个服务器端线程,用以做上下文。spring 的数据库连接管理,hibernate的session管理。ThreadLocal模式解决的是同一线程中隶属于不同开发层次的数据共享问题,而不是在不同的开发层次中进行数据传递。

    3.5 数据共享 OR 数据传递

      ThreadLocal模式与synchronized关键字都是用于处理多线程并发访问变量的问题。只是两者处理问题的角度和思路不同。
    (1)ThreadLocal是一个Java类,通过对当前线程(Thread)中的局部变量的操作来解决不同线程的变量访问的冲突问题。所以,ThreadLocal提供了线程安全的共享对象机制,每个线程(Thread)都拥有其副本。
    (2)Java中的synchronized是一个保留字,它依靠JVM的锁机制来实现临界区的函数或者变量在访问中的原子性。在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。此时,被用作“锁机制”的变量是多个线程共享的。
      同步机制采用了“以时间换空间”的方式,提供一份变量,让不同的线程排队访问。而ThreadLocal采用了“以空间换时间”的方式,为每一个线程都提供了一份变量的副本,从而实现同时访问而互不影响。

  • 相关阅读:
    c++中的.hpp文件
    最近用vs使用的比较好的工具
    new内存分配失败
    "0x%08x" C语言
    python爬取智联招聘工作岗位信息
    GIS应用1000例01序
    lxml 中连续调用xpath出的问题
    arcgis JavaScript API总体结构
    PostgreSQL安装
    ES6转ES5的babel的使用
  • 原文地址:https://www.cnblogs.com/ironyoda/p/6289898.html
Copyright © 2020-2023  润新知