线程安全

Java多线程编程(3)--线程安全性

核能气质少年 提交于 2020-01-05 03:31:10
一.线程安全性   一般而言,如果一个类在单线程环境下能够运作正常,并且在多线程环境下,在其使用方不必为其做任何改变的情况下也能运作正常,那么我们就称其是线程安全的。反之,如果一个类在单线程环境下运作正常而在多线程环境下则无法正常运作,那么这个类就是非线程安全的。因此, 一个类如果能够导致竞态,那么它就是非线程安全的;而一个类如果是线程安全的,那么它就不会导致竞态。下面是《Java并发编程实战》一书中给出的对于线程安全的定义: 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。   使用一个类的时候我们必须先弄清楚这个类是否是线程安全的。因为这关系到我们如何正确使用这些类。Java标准库中的一些类如ArrayList、HashMap和SimpleDateFormat,都是非线程安全的,在多线程环境下直接使用它们可能导致一些非预期的结果,甚至是一些灾难性的结果。一般来说,Java标准库中的类在其API文档中会说明其是否是线程安全的(没有说明其是否是线程安全的,则可能是也可能不是线程安全的)。   从线程安全的定义上我们不难看出,如果一个线程安全的类在多线程环境下能够正常运作,那么它在单线程环境下也能正常运作。既然如此

[转]Java中常用的集合—初学者的你不可错过的精编整理

旧街凉风 提交于 2020-01-05 02:29:32
集合一直都是项目中非常常见的,我是一个Android开发者,集合对于我来说,在项目中使用的次数非常之多,因为使用的多,熟能生巧,所以这里呢!就给那些初学者整理一下Java当中常用的集合吧!   因为此篇文章是给初学者看到,所以对于集合的认识,我们就不从内存的角度去分析了,等你Java学到一定的时候,再去学习一下集合的底层实现,这会让成为一名更加牛的Java程序员。   在整理之前呢,我们先聊一聊为什么集合会这么常用?,集合这个概念,我们初次接触是在高中的数学当中,高中的集合具有以下知识点:   1、集合的含义:某些指定的对象集在一起就成为一个集合,其中每一个对象叫元素。   2、集合的中元素的三个特性:   ①.元素的确定性;②.元素的互异性;③.元素的无序性   说明: (1)对于一个给定的集合,集合中的元素是确定的,任何一个对象或者是或者不是这个给定的集合的元素。   (2)任何一个给定的集合中,任何两个元素都是不同的对象,相同的对象归入一个集合时,仅算一个元素。   (3)集合中的元素是平等的,没有先后顺序,因此判定两个集合是否一样,仅需比较它们的元素是否一样,不需考查排列顺序是否一样。   高中的集合理解起来很简单,高中的集合里面放到是一个一个具体的对象,集合当中对象与对象之间是不一样的,而且集合中对象的元素是杂乱无章的,顺序没有什么规律可循,因为高中集合是无序性的

java中数组以及集合

柔情痞子 提交于 2020-01-05 01:18:20
java中数组: 数组在Java里是一种特殊类型,有别于普通的“类的实例”的对象。但实际数组也是一种对象类型,int[]a = new int[5] a是在java栈中分配的引用变量,类型是int[] 数组类型,指向在堆里面地址连续的实际数组对象。 在内存中,数组存储在连续的区域内部,因为数组中每个元素的类型相同,则占用的内存大小也一致,所以在访问数组中的元素时可以直接根据数组在内存中的起始位置以及下标来计算元素的位置,因此数组的访问速度很高。数组必须要初始化才能使用,初始化之后JVM会自动分配默认值,引用变量默认值是null。 数组和集合的区别: 1》数组初始化之后大小固定,无法再改变,集合大小可以改变。 2》同一个数组只能存储同一种数据类型(基本类型/引用类型).集合不考虑泛型可以存储多种数据类型,集合是存储对象的,所以基本类型不能放入集合,可以使用基本类型的包装类型。 3》若程序时不知道究竟需要多少对象,需要在空间不足时自动扩增容量,则需要使用容器类库,array不适用。 数组和集合之间进行转化: toArray():将集合转化为数组。 Arrays.asList():将数组转化为集合. 集合的体系结构 List、Set、Map是这个集合体系中最主要的三个接口。 List和Set继承自Collection接口。 Map也属于集合系统,但和Collection接口不同。

并发编程之多线程线程安全(上)

拜拜、爱过 提交于 2020-01-04 06:14:09
1、为什么有线程安全问题? 当多个线程共享同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题。但是做读操作是不会发生数据冲突问题。 案例:现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果。 代码: public class NewThread1 implements Runnable{ private int trainCount = 100; @Override public void run() { while (trainCount>0){ try { Thread.sleep(100); }catch (Exception e){ } save(); } } private void save() { if (trainCount > 0) { System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - trainCount + 1) + "张票"); trainCount--; } } public static void main(String[] args){ NewThread1 newThread1 = new NewThread1(); Thread thread1 = new Thread(newThread1,"①");

系统学习java高并发系列三

与世无争的帅哥 提交于 2020-01-04 05:13:18
转载请注明原创出处,谢谢! 首先需要说说线程安全?关于线程安全一直在提,比如StringBuilder和StringBuffer有什么区别? 经常就会出现关于线程安全与线程非安全,可能一直在提自己没有细细想想, 如果忽然问你啥是线程安全的概念? 可能你需要短暂停顿几秒,线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据,其实关于线程安全的定义我想不到好的,百度了下,也没有发现一个特别好的解释,我就选择一个相对来说还可以的解释吧 ,线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。我觉得该描述也不完全正确,因为现在控制并发的策略很多不仅仅是加锁机制,也可以不用加锁,我觉得这样可能比较合适的解释,就是多个线程都会操作到的,是一个公共资源或者共享的数据,但是每次操作只能一个线程使用而一旦临界区资源被占用其他的线程必须等待该资源的释放,在并行程序中,临界区资源都是受保护的那么就是线程安全,不包含的就是线程不安全的。 由于并发程序要比串行程序复杂很多,一个最重要的原因就是并发程序下访问的一致性和安全性将会受到严重挑战,如何保证一个线程可以看到正确的数据呢?因此我们需要深入了解并行机制的前提下,在定义一些规则来保证多线程直接有效的

Volatile 说明

元气小坏坏 提交于 2020-01-04 02:51:08
Java™ 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。 Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized ”;与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分。本文介绍了几种有效使用 volatile 变量的模式,并强调了几种不适合使用 volatile 变量的情形。 锁提供了两种主要特性: 互斥(mutual exclusion) 和 可见性(visibility) 。互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。可见性要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 —— 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题。 Volatile 变量 Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现

设计模式之单例模式——只有一个实例

孤人 提交于 2020-01-04 00:20:15
目录 一 单例模式简介 1.1 定义 1.2 为什么要用单例模式呢? 1.3 为什么不使用全局变量确保一个类只有一个实例呢? 二 单例的模式的实现 2.1 饿汉方式(线程安全) 2.2 懒汉式(非线程安全和synchronized关键字线程安全版本 ) 2.3 懒汉式(双重检查加锁版本) 2.4 懒汉式(登记式/静态内部类方式) 2.5 饿汉式(枚举方式) 2.6 总结 一 单例模式简介 1.1 定义 保证一个类仅有一个实例,并提供一个访问它的全局访问点。 1.2 为什么要用单例模式呢? 在我们的系统中,有一些对象其实我们只需要一个,比如说: 线程池、缓存、对话框、注册表、日志对象、充当打印机、显卡等设备驱动程序的对象。事实上,这一类对象只能有一个实例,如果制造出多个实例就可能会导致一些问题的产生,比如:程序的行为异常、资源使用过量、或者不一致性的结果。 简单来说使用单例模式可以带来下面几个好处: 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销; 由于 new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间。 1.3 为什么不使用全局变量确保一个类只有一个实例呢? 我们知道全局变量分为静态变量和实例变量,静态变量也可以保证该类的实例只存在一个。 只要程序加载了类的字节码

java虚拟机——线程安全

匆匆过客 提交于 2020-01-03 04:02:18
java虚拟机——线程安全 java语言中各种操作共享的数据分为以下5类:不可变、绝对线程安全、相对线程安全、线程兼容、线程对立 1、不可变:不可变的对象一定是线程安全的。不需要采取任何的线程安全保障措施。 2、绝对线程安全:不管运行环境如何,调用者都不需要任何额外的同步措施 3、相对线程安全:对该对象单独的操作是线程安全的,在调用时不需要额外的保障措施。对于伊特特定顺序的连续调用,在调用端使用额外的同步手段来保证调用的正确性。 4、线程兼容:对象本身并不是线程安全的,可以通过在调用端正确的使用同步手段来保证对象在并发环境中可以安全地使用。 5、线程对立:无论调用端是否采取了同步措施,都无法在多线程环境中并发使用的代码。 线程安全的实现方法 1、互斥同步 保证共享数据在一个时刻只被一个线程使用。 实现手段:临界区、互斥量(mutex),信号量(semaphore) 最基本的互斥同步手段是synchronized关键字。 java的线程是映射到操作系统的原生线程之上的,如果要阻塞或唤醒一个线程,都需要操作系统帮忙,就需要从用户转换到内核态,因此状态转换需要耗费很多的处理器时间。因此,synchronized是java的一个重量级操作。 2、非阻塞同步 互斥同步是阻塞同步,主要问题是进行线程阻塞和唤醒所带来的的性能问题。 非阻塞同步——基于冲突检测的乐观并发策略:先进行操作

Software Construction Series (5)

 ̄綄美尐妖づ 提交于 2020-01-02 00:40:06
在编写多线程的时候遇到这样一个问题,在多个线程中往同一个集合中添加元素,最后在统一遍历进行处理。然而在实际运行中可有能会出现报错:NullPointerException || IndexOutOfBoundsException。然而在添加元素和遍历元素的过程中理应是不可能出现这样的问题的。 但是考虑到多线程,其实可能出现这样一种情况: List<Integer> l = new ArrayList<>(); public void add(int x) { assert l.size() == 0; l.add(x); } add方法是可以在多线程中正常运行,并且不报错的,即在每个线程执行到add方法时,l.size() == 0。 这样就会在集合同一个位置多次添加,面对更复杂的数据结构,是会出现bug的。 既然知道了原因,就要有相应的解决办法: JDK提供了对于线程安全的集合类,在JDK1.5之前多线程方面的处理比较简单,只有thread和synchronized两种机制。其中线程安全的集合类是: List l = Collections.synchronizedList(new ArrayList<>()); Set s=Collections.synchronizedSet(new HashSet()); Map m=Collections.synchronizedMap

设计模式--单例模式

我的未来我决定 提交于 2020-01-02 00:29:31
所谓类的单例设计模式,就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。 单例模式一共有八种实现方式 1)饿汉式(静态常量) 2)饿汉式(静态代码块) 3)懒汉式(线程不安全) 4)懒汉式(线程安全,同步方法) 5)懒汉式(线程安全,同步代码块)错误,可能出现多个实例 6)双重检查 7)静态内部类 8)枚举 饿汉式会在反射或序列化反序列化时破坏单例 一、饿汉式(静态常量) 优缺点说明: 1)优点:写法简单,在类装载的时候就完成实例化。避免了线程同步问题。 2)缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终没用使用过这个实例,则会造成内存的浪费。 3)这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,在单例模式中大多数都是调用getInstance方法,但是导致类装载的原因有很多种,因此不能确定有其他的方法(或者其它的静态方法)导致类装载,这时候初始化isntance就没有达到lazy loading的效果。 4)结论:这种单例模式可用,可能造成内存浪费。 二、饿汉式(静态代码块) 优缺点同饿汉式(静态常量) 三、懒汉式(线程不安全) 四、懒汉式(线程安全,同步方法) 优缺点说明: 1)解决了线程不安全的问题 2