线程安全

理解什么是线程安全性、原子性

只愿长相守 提交于 2020-01-24 08:47:08
目录 •写在前面 •原子性 加锁机制 •写在前面 进程想要执行任务需要依赖线程,换句话说就是进程中的最小执行单位就是线程,并且一个进程中至少有一个线程。提到多线程这里要说两个概念,就是串行和并行,搞清楚这个我们才能更好的理解多线程。所谓串行其实是相对于单条线程来执行多个任务来说的,我们就拿下载文件来举个例子,我们下载多个文件,在串行中它是按照一定的顺序去进行下载的,也就是说必须等下载完A之后,才能开始下载B,它们在时间上是不可能发生重叠的。 要编写线程安全的代码,其核心在于要对状态访问操作进行管理,特别是对共享的和可变的状态的访问。要是的对象是线程安全的,需要采用同步机制来协同对对象可变状态的访问,如果无法实现协同,那么可能会导致数据破坏以及其他不该出现的结果。java中的同步机制是关键字synchronized,它提供了独占式的加锁方式,不仅如此还包括volatile类型变量,显式锁Lock以及原子变量。 单线程近似定义为“所见即所知”,那么定义线程安全性,则当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。一个类在单线程中运行都不正确,那么它肯定是不会是线程安全的。如果正确的实现了某个对象,那么在任何操作中(包括调用对象的公有方法或者对其公有域进行读写操作)都不会违背不变性条件或后验条件

【WP8】线程安全的StorageHelper

杀马特。学长 韩版系。学妹 提交于 2020-01-23 14:31:40
14-08-29 12:32更新:修复StorageHelper部分bug WP8以后提供了StorageFile的方式访问文件,StorageFile对文件的操作只提供了异步的支持,包括WP8.1 RT也没有对同步读写文件的支持,可以看出异步在移动开发中的重要性,而且Win8也是通过StorageFile进行文件操作的 跟WP7上的IsolatedStorageFile相比,StorageFile使用起来并不方便,最近总结了一些资料,写了一个通用的类库 StorageFile默认是线程不安全的,如果多个线程同时对文件进行读写会抛出异常,例如多图的场景比较常见 让StorageFile使用起来更加方便,同时提供了 线程安全 的异步操作,同时也对IsolatedStorageFile(Silverlight)进行了封装 一、StorageFile要点:   StorageFile     1、访问文件(两种方式) //访问安装目录下的test.txt文件,如果不存在,会抛出FileNotFoundException异常 //1、访问当前目录下的文件 var folder = Package.Current.InstalledLocation; var storageFile = await folder.GetFileAsync("test.txt"); //2、通过Uri访问文件

什么是乐观锁和悲观锁?

孤街浪徒 提交于 2020-01-23 03:56:10
乐观锁:对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将比较-替换(CAS)这两个动作作为一个原子操作尝试去修改内存中的变量,如果失败则表示发生冲突,那么就应该有相应的重试逻辑。 悲观锁:对于并发间操作产生的线程安全问题持悲观状态,悲观锁认为竞争总是会发生,因此每次对某资源进行操作时,都会持有一个独占的锁,就像 synchronized、Reentrylock。 来源: CSDN 作者: 逍遥书虫 链接: https://blog.csdn.net/baidu_28370189/article/details/103946204

详解单例模式六种写法的优缺点

情到浓时终转凉″ 提交于 2020-01-23 03:46:40
前言 单例模式:保证一个类有且仅有一个实例. 通过定义我们可知它是创建型的一种, 也是比较简单的一种 单例模式的使用场景: 频繁的进行创建和销毁的对象、创建对象时消耗过多或者消费资源过多,但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象. 下面主要分析一下单例模式的六种写法, 以及优缺点! 饿汉式(静态常量) 懒汉式(线程不安全) 懒汉式(线程安全) 双重检查 静态内部类 枚举 饿汉式(静态常量) 代码 //饿汉式(静态常量) class Singleton { // 构造器私有 外部不能实例化 private Singleton ( ) { } private final static Singleton instance = new Singleton ( ) ; public static Singleton getInstance ( ) { return instance ; } } 优点 写法简单, 在类装载的时候完成了实例化 避免了线程同步问题 缺点 导致类装载的原因有很多种, 不能达到 lazy loading(懒加载)的效果 有可能造成内存浪费 懒汉式(线程不安全) 代码 //懒汉式 class Singleton { private static Singleton instance ; private Singleton ( ) { } public

Java面试题-并发篇十六

孤者浪人 提交于 2020-01-23 03:39:17
161,Java内存模型是什么? Java内存模型规定和指引Java程序在不同的内存架构、CPU和操作系统间有确定性地行为。它在多线程的情况下尤其重要。Java内存模型对一个线程所做的变动能被其它线程可见提供了保证,它们之间是先行发生关系。这个关系定义了一些规则让程序员在并发编程时思路更清晰。比如,先行发生关系确保了: 线程内的代码能够按先后顺序执行,这被称为程序次序规则。 对于同一个锁,一个解锁操作一定要发生在时间上后发生的另一个锁定操作之前,也叫做管程锁定规则。 前一个对volatile的写操作在后一个volatile的读操作之前,也叫volatile变量规则。 一个线程内的任何操作必需在这个线程的start()调用之后,也叫作线程启动规则。 一个线程的所有操作都会在线程终止之前,线程终止规则。 一个对象的终结操作必需在这个对象构造完成之后,也叫对象终结规则。 可传递性 更多介绍可以移步并发编程网: (深入理解java内存模型系列文章:http://ifeve.com/java-memory-model-0) 162,Java中interrupted 和isInterruptedd方法的区别? interrupted() 和 isInterrupted()的主要区别是前者会将中断状态清除而后者不会。Java多线程的中断机制是用内部标识来实现的,调用Thread

JUC高并发与线程安全(1)

我是研究僧i 提交于 2020-01-22 20:24:30
JUC高并发 1、谈谈你对volatile的理解 1.1volatile是Java虚拟机提供的轻量级的同步机制 1.1.1保证可见性 在内存模型中,线程将自身需要的对象数据从主机物理内存拷贝到线程工作内存(实际仍在物理内存,虚拟的划分约定),当线程对数据的修改经历三个步骤: 从物理内存拷贝数据到工作内存 在执行线程中修改数据 将数据写回物理内存 数据写完后,需要及时的通知其他需要此对象的线程,“该数据已更改,请重新加载”,这就是数据可见性 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8gEIEbLQ-1577715678426)(C:\Users\Kin\AppData\Roaming\Typora\typora-user-images\1577408098733.png)] 验证可见性 class Mydata { int num = 0 ; //添加volatile关键字再次测试 //volatile int num=0; public void initTo10 ( ) { this . num = 10 ; } public void numPlusPlus ( ) { this . num ++ ; } } public class VolatileDemo { public static void main ( String [ ]

String 和 StringBuffer、StringBuilder 的区别是什么?String 为什 么是不可变的?

戏子无情 提交于 2020-01-22 20:07:59
可变性 String类中使用final关键字字符数组 private final char value[] 保存字符串 ,因此String对象是不可变的。 而StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串 char[]value 但是没有用 final 关键字修饰,所以这两种对象都是可变的。 线程安全性 String中的对象不可变,线程安全 StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。 StringBuilder 并没有对 方法进行加同步锁,所以是非线程安全的。 性能 每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。 StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 StirngBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。 总结: 1. 操作少量的数据 = String 2. 单线程操作字符串缓冲区下操作大量数据 = StringBuilder 3.

Java 多线程、线程安全实例

这一生的挚爱 提交于 2020-01-22 19:36:06
创建线程 Java使用 java.lang.Thread 类代表线程,所有的线程对象都必须是Thread类或其子类的实例。 Thread类 public class MyThread extends Thread { public MyThread ( String name ) { //调用父类的String参数的构造方法,指定线程的名称 super ( name ) ; } /** * 重写run方法,完成该线程执行的逻辑 */ @Override public void run ( ) { try { sleep ( 10 ) ; } catch ( InterruptedException e ) { e . printStackTrace ( ) ; } for ( int i = 0 ; i < 100 ; i ++ ) { System . out . println ( getName ( ) + i ) ; } } } public class ThreadTest { public static void main ( String [ ] args ) { //创建自定义线程对象 MyThread mt1 = new MyThread ( "a" ) ; MyThread mt2 = new MyThread ( "b" ) ; MyThread mt3 =

设计模式之单例设计模式

大城市里の小女人 提交于 2020-01-22 17:02:24
单例模式 ,就是只有一个实例对象存在,保证了多线程情况下的线程安全问题。保证一个类仅有一个实例,并提供一个访问它的全局访问点。 创建单例对象的三要素: 单例类只能有一个实例。 单例类必须自己创建自己的唯一实例。 单例类必须给所有其他对象提供这一实例。 主要应用场景: Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。 一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。 要求生产唯一序列号。 WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。 实现单列模式的关键 : 私有构造方法 单例模式的七种实现方式: 单例模式 主要分为 饿汉式 和 懒汉式 两种 单列模式主要考虑 实例对象唯一 懒加载 性能问题 1、饿汉式 这是饿汉式的简单实现保证了线程安全,但是浪费内存的开销,没有实现懒加载。 package com . multi . thread . two . design . pattern ; /** * 饿汉式:实现步骤 * 1、私有构造方法 * 2、新建实例对象 * 3、对外提供获取对象的全局访问点 * 保证线程安全, *

如何在匿名thread子类中保证线程安全

微笑、不失礼 提交于 2020-01-22 13:04:58
在做性能测试的过程中,我写了两个虚拟类 ThreadLimitTimeCount 和 ThreadLimitTimesCount 做框架,通过对线程的标记来完成超时请求的记录。旧方法如下: @Override protected void after() { requestMark.addAll(marks); marks = new ArrayList<>(); GCThread.stop(); synchronized (this.getClass()) { if (countDownLatch.getCount() == 0 && requestMark.size() != 0) { Save.saveStringList(requestMark, MARK_Path.replace(LONG_Path, EMPTY) + Time.getDate().replace(SPACE_1, CONNECTOR)); requestMark = new Vector<>(); } } } 其中我用了 synchronized 关键字同步,但是在匿名类的单元测试中出现一个BUG,匿名类中没有实现 clone() 方法,也不能直接使用深拷贝方法,导致无法直接复制对象,所以我创建了多个功能相同的匿名线程类。问题来了,在代码执行过程中,偶然会出现记录 markrequest