Java线程安全基础概念解析

Java线程安全初步了解。JAVA线程安全从总体上来说,是指Java对象在多线程运行环境下的一种特性,表现为常规(区别于特殊调用情况)情况下每次调用都能得到正确的逻辑结果。从本质上来说,将对象的方法行为加上了同步控制逻辑,而调用者无须做其他额外的同步控制就可以安全放心的使用对象。

1.线程安全的定义

当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安全的。这个定义很严谨,它要求就线程安全的代码都具备一个特征:代码本身封装了所有必要的正确性保障手段,令调用者无须关心多线程的问题,更无须自己实现热河措施来保证多线程的正确调用。

2.Java语言中的线程安全

为了更深入地理解线程安全,按照线程安全的“安全强度”由强至弱来排序:不可变,绝对线程安全,相对线程安全,线程兼容和线程对立。

2.1 不可变

在jDK1.5以后不可变的对象一定是线程安全的,无论是对象的方法实现还是方法的调用者,都不需要再进行任何的线程安全保障措施,通过final关键字修饰的属性,对象或方法,那其外部的可见状态永远也不会改变。如果共享数据是一个基本数据类型,那么只要在定义时使用final关键字修饰就可以保证它是不可变得。如String类对象,就是一个典型的不可变对象,我们调用substring(),replace(),和concat()这些方法都不会影响它原来的值,只会返回一个新构造的字符串对象。

2.2相对线程安全

相对线程安全就是我们通常意义上所讲的线程安全,它需要保证这个对象单独的操作是线程安全的。在java中大部分线程安全类都属于这种类型,如Vector,HashTable等。

2.3线程兼容

线程兼容是指对象本身并不是线程安全的,但是可以通过在调用端正确地使用同步手段来保证对象在并发环境中安全地使用。

2.3线程对立

线程对立是指不管调用端是否采用了同步措施,都无法在多线程环境中并发使用的代码。由于Java语言天生就具备多线程特性,线程对立这种排斥多线程的代码很少出现。常见的线程对立操作有Thread类的suspend()和resume()方法,System.setIn()等。

3.线程安全的实现方法

3.1互斥同步

互斥同步是最常见的一种并发正确性保障手段,同步是指在多个线程并发访问共享数据时,保证共享数据在同一个时刻只被一条线程使用。而互斥是实现同步的一种手段,临界区,互斥量和信号量都是主要的互斥实现方式。互斥是因,同步是果,互斥是方法,同步是目的。

在Java中,最基本的互斥同步手段就是synchronized关键字。除此之外还可以使用java.util.concurrent包中的重入锁(ReentrantLock)来实现同步。在用法上都很相似,只是代码写法上有点区别,一个表现为API层面的互斥锁(lock()和unlock()方法配合try/finally语句块来完成),一个表现为原生语法层面的互斥锁。不过重入锁比synchronized增加了以下三项:
等待可中断:是指当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情,可中断特性对处理执行时间非常长的同步块很有帮助。

可实现公平锁:公平锁是指多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁;而非公平锁则不保证这一点。synchronized中的锁是非公平的,重入锁缺省也是非公平的,但可以通过带布尔值的构造函数要求使用公平锁。

锁可以绑定多个条件:是指一个重入锁对象可以同时绑定多个Condition对象,而在synchronized中,锁对象的wait()和notify()或notifyAll()方法可以实现一个隐含条件,如果要和多于一个的条件关联的时候,就不得不额外的添加y一个锁,而重入锁无须这样做,只需要多次调用newCondition()方法即可。

3.2非阻塞同步

互斥同步最重要的问题就是进行线程阻塞和唤醒所带来的性能问题,它属于一种悲观的并发策略,总是认为只要不去做正确的同步措施就会出现问题。但是我们有了另外一个选择:基于冲突检测的乐观并发策略,通俗的说就是先进行操作,如果没有其他线程争用共享数据,那操作就成功了;如果共享数据发生了争用,产生了冲突,那就再进行其他的补偿措施,这种乐观的并发策略的许多实现都不需要把线程挂起,因此被称为非阻塞同步。

总结

以上就是本文关于Java线程安全基础概念解析的全部内容了,希望对大家有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • java中volatile不能保证线程安全(实例讲解)

    今天打了打代码研究了一下java的volatile关键字到底能不能保证线程安全,经过实践,volatile是不能保证线程安全的,它只是保证了数据的可见性,不会再缓存,每个线程都是从主存中读到的数据,而不是从缓存中读取的数据,附上代码如下,当synchronized去掉的时候,每个线程的结果是乱的,加上的时候结果才是正确的. /** * * 类简要描述 * * <p> * 类详细描述 * </p> * * @author think * */ public class Volatil

  • java多线程之线程安全的单例模式

    概念: java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例.饿汉式单例.登记式单例三种. 单例模式有一下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管理器的功能.每台计算机可以有若干个打印机,但只能有一个Printer

  • Java 集合中的类关于线程安全

    Java集合中那些类是线程安全的 线程安全类 在集合框架中,有些类是线程安全的,这些都是jdk1.1中的出现的.在jdk1.2之后,就出现许许多多非线程安全的类. 下面是这些线程安全的同步的类: vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用.在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的. statck:堆栈类,先进后出 hashtable:就比hashmap多了个线程安全 enumeration:枚举,相当于迭代器

  • Java ThreadLocal 线程安全问题解决方案

    一.线程安全问题产生的原因 线程安全问题都是由全局变量及静态变量引起的 二.线程安全问题 SimpleDateFormate sdf = new SimpleDateFormat();使用sdf.parse(dateStr);sdf.format(date);在sdf内有一个对Caleadar对象的引用,在源码sdf.parse(dateStr);源码中calendar.clear();和calendar.getTime(); // 获取calendar的时间 如果 线程A 调用了 sdf.pa

  • 解析Java线程编程中的线程安全与synchronized的使用

    一.什么时候会出现线程安全问题? 在单线程中不会出现线程安全问题,而在多线程编程中,有可能会出现同时访问同一个资源的情况,这种资源可以是各种类型的的资源:一个变量.一个对象.一个文件.一个数据库表等,而当多个线程同时访问同一个资源的时候,就会存在一个问题: 由于每个线程执行的过程是不可控的,所以很可能导致最终的结果与实际上的愿望相违背或者直接导致程序出错. 举个简单的例子: 现在有两个线程分别从网络上读取数据,然后插入一张数据库表中,要求不能插入重复的数据. 那么必然在插入数据的过程中存在两个操

  • Java线程安全基础概念解析

    Java线程安全初步了解.JAVA线程安全从总体上来说,是指Java对象在多线程运行环境下的一种特性,表现为常规(区别于特殊调用情况)情况下每次调用都能得到正确的逻辑结果.从本质上来说,将对象的方法行为加上了同步控制逻辑,而调用者无须做其他额外的同步控制就可以安全放心的使用对象. 1.线程安全的定义 当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安

  • java线程的基础实例解析

    java中建立线程可以有两种方式,分别是继承Thread类和实现Runnable接口. 继承Thread public class MyThread extends Thread{ public MyThread(String name){ super(name); } int i; public void run(){ for(i=0;i<5;i++){ System.out.println(getName()+"--"+i); } } public static void m

  • java语言注解基础概念详解

    1.RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃: 2.RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期: 3.RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在: 这3个生命周期分别对应于:Java源文件(.java文件)--->.class文件--->内存中的字节码.

  • Java线程状态运行原理解析

    这篇文章主要介绍了Java线程状态运行原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 代码实例如下 package com.fgy.demo05; /** * 等待唤醒案例:线程之间通信 * 注意: * 同步使用的锁对象必须唯一 * 只有锁对象才能调用wait和notify()/notifyAll()方法 */ public class Demo1WaitAndNotify { public static void main(Strin

  • Java线程池ForkJoinPool实例解析

    这篇文章主要介绍了Java线程池ForkJoinPool实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 背景:ForkJoinPool的优势在于,可以充分利用多cpu,多核cpu的优势,把一个任务拆分成多个"小任务",把多个"小任务"放到多个处理器核心上并行执行:当多个"小任务"执行完成之后,再将这些执行结果合并起来即可.这种思想值得学习. import java.io.IOExcept

  • Java线程安全状态专题解析

    一.观察线程的所有状态 线程的状态是一个枚举类型 Thread.State public static void main(String[] args) { for (Thread.State state : Thread.State.values()){ System.out.println(state); } } NEW: 安排了工作, 还未开始行动 RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作.就绪状态 BLOCKED: 这几个都表示排队等着其他事情 WAITING:

  • Java线程的基本概念

    在之前的章节中,我们都是假设程序中只有一条执行流,程序从main方法的第一条语句逐条执行直到结束.从本节开始,我们讨论并发,在程序中创建线程来启动多条执行流,并发和线程是一个复杂的话题,本节,我们先来讨论Java中线程的一些基本概念. 创建线程 线程表示一条单独的执行流,它有自己的程序执行计数器,有自己的栈.下面,我们通过创建线程来对线程建立一个直观感受,在Java中创建线程有两种方式,一种是继承Thread,另外一种是实现Runnable接口,我们先来看第一种. 继承Thread Java中j

  • 浅谈Java线程Thread.join方法解析

    join字面上是加入的意思,我们先看看join方法的解释和实现. /** * Waits for this thread to die. * 调用方线程(调用join方法的线程)执行等待操作,直到被调用的线程(join方法所属的线程)结束,再被唤醒 * <p> An invocation of this method behaves in exactly the same * way as the invocation * * * @throws InterruptedException *

  • Java线程的相关方法详细解析

    start()  启动线程方法 run()  调用start()方法时,真正执行的就是该方法的方法体 sleep()  让当前线程睡眠,睡眠到期自动苏醒,并进入可运行状态,而不是运行状态 yield() 暂停当前正在执行的线程对象,JVM线程调度程序基于优先级的抢先机制调用其他优先级高的线程,优先级的取值范围1 (Thread.MIN_PRIORITY) -- 10( Thread.MAX_PRIORITY),创建线程默认是5 (NORM_PRIORITY) setPriority(int ne

  • Java中一些基础概念的使用详解

    类的初始化顺序 在Java中,类里面可能包含:静态变量,静态初始化块,成员变量,初始化块,构造函数.在类之间可能存在着继承关系,那么当我们实例化一个对象时,上述各部分的加载顺序是怎样的? 首先来看代码: 复制代码 代码如下: class Parent {     public static StaticVarible staticVarible= new StaticVarible("父类-静态变量1");         public StaticVarible instVaribl

随机推荐