一、线程的调度方式

  线程调度分为两种方式: 协同式调度和抢占式调度。
协同式调度:线程的执行时间由线程本身控制,线程将工作执行完之后,通知操作系统切换到其他线程上。缺点:时间不可控,就算出问题,也不会通知操作系统切换,容易阻塞。
抢占式调度:每个线程由操作系统来分配执行时间,调度。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采用了“以空间换时间”的方式,为每一个线程都提供了一份变量的副本,从而实现同时访问而互不影响。

JVM线程安全的更多相关文章

  1. 【操作系统】二、JVM线程与Linux内核线程的映射

    Linux从内核2.6开始使用NPTL (Native POSIX Thread Library)支持,但这时线程本质上还轻量级进程. Java里的线程是由JVM来管理的,它如何对应到操作系统的线程是 ...

  2. JVM线程状态,park, wait, sleep, interrupt, yeild 对比

    ---恢复内容开始--- JVM线程状态 NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED BLOCKED是等待获得对象锁 WAIT ...

  3. JVM线程与Linux内核线程的映射[转]

    Linux从内核2.6开始使用NPTL (Native POSIX Thread Library)支持,但这时线程本质上还轻量级进程. Java里的线程是由JVM来管理的,它如何对应到操作系统的线程是 ...

  4. JVM线程状态Running、Sleeping、Wait、Park、Monitor

    1,使用JVisualVM时,打开Threads监控,我们可以发现Java的线程状态有以下几种: 2,JVM线程状态: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_W ...

  5. 深入理解JVM线程模型

    1. jvm内存模型在描述jvm线程模型之前,我们先深入的理解下,jvm内存模型.在jvm1.8之前,jvm的逻辑结构和物理结构是对应的.即Jvm在初始化的时候,会为堆(heap),栈(stack), ...

  6. 任务队列方案详解(一)JVM线程池

    前言 我们都知道 web 服务的工作大多是接受 http 请求,并返回处理后的结果.服务器接受的每一个请求又可以看是一个任务.一般而言这些请求任务会根据请求的先后有序处理,如果请求任务的处理比较耗时, ...

  7. jvm 线程实现机制

    简单记一下 实际上jvm 规范中并无做限制. 不同的jvm实现上存在一定差异.技术上的选择主要在 jvm的线程是如何和操作系统的线程对应的.有1:1 的线程实现模式,也有N:1的线程实现模式,更有M: ...

  8. 【转】java jvm 线程 与操作系统线程

    原文链接:http://segmentfault.com/q/1010000000370403 Java的目标是要跨平台,而不同的操作系统(如类Unix和Windows)其任务调度机制有很大的不同,故 ...

  9. [Java Performance] JVM 线程调优

    调整线程栈空间 当很缺少内存时,能够调整线程使用的内存. 每一个线程都有一个栈,用来记录该线程的调用栈信息.线程中的栈的默认空间是有OS和JVM的版本号决定的: OS 32-bit 64-bit Li ...

随机推荐

  1. Dense Subsequence

    Dense Subsequence time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...

  2. Dynamic Performance Tables not accessible Automatic Statistics disabled for this session

    使用oracle时候统计会出现这个提示 Dynamic Performance Tables not accessible Automatic Statistics disabled for this ...

  3. if __name__ == '__main__'在python中的应用

    当你打开一个.py文件时,经常会在代码的最下面看到if __name__ == '__main__':,现在就来介 绍一下它的作用. 模块是对象,并且所有的模块都有一个内置属性 __name__.一个 ...

  4. 将所需要的图标排成一列组成一张图片,方便管理。li的妙用

    我在做一个网站的header 但是视频教学里面将电话图标,微信图标,以及每一个英文字母右边的小点拼成一副图. (图片的名字是top_ioc.png)拼成的整个图片作为li的背景.通过移动就可以分别将每 ...

  5. windows程序设计(二)

    MFC架构组成 1.CWinApp的派生类 2.必须在全局区定义一个派生类的对象 3.在CWinApp派生类内必须要有InitInstance虚函数的重写函数 在MFC软件工程以App类中的InitI ...

  6. redis五种数据类型的使用

    redis五种数据类型的使用 redis五种数据类型的使用 (摘自:http://tech.it168.com/a2011/0818/1234/000001234478_all.shtml ) 1.S ...

  7. Bootstrap 模态对话框只加载一次 remote 数据的解决办法 转载

    http://my.oschina.net/qczhang/blog/190215 摘要 前端框架 Bootstrap 的模态对话框,可以使用 remote 选项指定一个 URL,这样对话框在第一次弹 ...

  8. MYSQL启用日志,查看日志,利用mysqlbinlog工具恢复MySQL数据库【转载】

    转自 MYSQL启用日志,查看日志,利用mysqlbinlog工具恢复MySQL数据库 - _安静 - 博客园http://www.cnblogs.com/xionghui/archive/2012/ ...

  9. github 教程

    http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/

  10. emacs command

    eval-buffer用来执行.emacs不要再重启了,或cxce执行光标前的一行 eval-region load-file ~/.emacs goto-line global-set-key定义快 ...