Java中的线程安全和非线程安全以及锁的几个知识点
1. 线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是“脏”数据。
比方说ArrayList是非线程安全的,Vector是线程安全的;HashMap是非线程安全的,HashVector是线程安全的;StringBuilder是非线程安全的,StringBuffer是线程安全的。
2. 线程安全是通过线程同步来控制的,也就是synchronized关键字,因此会导致性能的降低,所以使用的时候如果是多个线程操作一个对象,那么就使用线程安全的Vector,否则就使用效率更高的ArrayList。
需要注意的是非线程安全并不等于不安全,因为我如果每个线程都有一个自己的ArrayList,各自不会访问,那么用ArrayList是没有问题的。
3. 锁的几个机制:
1.可重入锁:基于线程分配锁,而不是根据方法的调用来进行分配
class Main
{
public synchronized void method1()
{
method2();
} public synchronized void method2()
{
}
}
假如某一时刻,线程A执行到了method1,此时线程A获取了这个对象的锁,而由于method2也是synchronized方法,假如synchronized不具备可重入性,此时线程A需要重新申请锁。但是这就会造成一个问题,因为线程A已经持有了该对象的锁,而又在申请获取该对象的锁,这样就会线程A一直等待永远不会获取到的锁。
2.可中断锁
如果某一线程A正在执行锁中的代码,另一线程B正在等待获取该锁,可能由于等待时间过长,线程B不想等待了,我们可以让它中断自己或者在别的线程中中断它,这种就是可中断锁。synchronized就不是可中断锁,而Lock是可中断锁。
3.公平锁
尽量以请求锁的顺序来获取锁。比如同是有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该所,这种就是公平锁。相对的就有非公平锁,如synchronized就是非公平锁
4. 了解一下Synchronized
大致的描述一下,个人感觉被Synchronized修饰的线程或者代码块,就只能一个人单独访问,其他人想访问就必须等到找个人使用完交给下一个人。这样的好处就是对于很多线程共用的一些变量不会出现几个线程同时在修改它,比方说我们的临界区元素和变量。它的最大的特征就是在同一时刻只有一个线程能够获得对象的监视器,从而进入到同步代码块或者同步方法之中。
但是这样也会有一个问题,打个比方,我们在购物的时候排队,大家要是都到结账的时候才从钱包掏钱就不如自己先把自己的付款二维码准备好的效率快,就是使用Synchronized修饰的话运行时候效率会变低,这个时候我们可以了解下一个知识点:悲观锁和乐观锁。
1.悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。Synchronized就是悲观锁。
2.乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。但是这样会有一个问题就是可能会出现冲突,就是你假设归你假设,别人不一定这么乖。所以我们利用版本号和CAS操作来实现这个。
CAS设计到三个操作数::V 内存地址存放的实际值;O 预期的值(旧值);N 更新的新值。当V和O相同时,也就是说旧值和内存中实际的值相同表明该值没有被其他线程更改过,即该旧值O就是目前来说最新的值了,自然而然可以将新值N赋值给V。反之,V和O不相同,表明该值已经被其他线程改过了则该旧值O不是最新版本的值了,所以不能将新值N赋给V,返回V即可。所以多个线程同时访问的时候就只会有一个线程成功。
实例理解一下:
比方说在内存地址V中,存放着值为10的变量,此时此时线程1想要把变量的值增加1。对线程1来说,旧的预期值A=10,要修改的新值B=11。在线程1要提交更新之前,另一个线程2抢先一步,把内存地址V中的变量值率先更新成了11。线程1开始提交更新,首先进行A和地址V的实际值比较(Compare),发现A不等于V的实际值,提交失败。线程1重新获取内存地址V的当前值,并重新计算想要修改的新值。此时对线程1来说,A=11,B=12。这个重新尝试的过程被称为自旋。这一次比较幸运,没有其他线程改变地址V的值。线程1进行Compare,发现A和地址V的实际值是相等的。线程1进行SWAP,把地址V的值替换为B,也就是12。
3.那么这两种锁应用场景:乐观锁的话简单的来说CAS适用于写比较少的情况下(多读场景,冲突一般较少),悲观锁如synchronized适用于写比较多的情况下(多写场景,冲突一般较多)
5. 上锁的话除了synchronized还要Lock操作
1.synchronized的缺点:当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,并且等待的线程是不能做其他事情的,会影响执行的效率。通过Lock可以让等待的进程一直等待下去。
2.Lock的几种方法:lock()方法是平常使用得最多的一个方法,就是用来获取锁;tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。unlock()释放锁,我们应该把释放锁的操作放在finally块中进行保证锁一定会被释放防止死锁的事情发生。
3.Lock和Synchronized的区别:
Lock不是Java语言内置的是一个接口,synchronized是Java语言的关键字,所以synchronized不需要用户去手动释放锁但是Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。
Lock可以让等待锁的线程响应中断,而synchronized却不行。
通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
Lock可以提高多个线程进行读操作的效率。
Java中的线程安全和非线程安全以及锁的几个知识点的更多相关文章
- JAVA中的线程安全与非线程安全
原文:http://blog.csdn.net/xiao__gui/article/details/8934832 ArrayList和Vector有什么区别?HashMap和HashTable有什么 ...
- 为什么JAVA虚拟机分为线程共享和非线程共享?
大多数 JVM 将内存区域划分为 Method Area(Non-Heap)(方法区) ,Heap(堆) , Program Counter Register(程序计数器) , VM Stack(虚拟 ...
- Java基础-Java中的并法库之线程池技术
Java基础-Java中的并法库之线程池技术 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是线程池技术 二.
- Java线程安全和非线程安全
ArrayList是非线程安全的,Vector是线程安全的:HashMap是非线程安全的,HashTable是线程安全的:StringBuilder是非线程安全的,StringBuffer是线程安全的 ...
- 转:Windows下的PHP开发环境搭建——PHP线程安全与非线程安全、Apache版本选择,及详解五种运行模式。
原文来自于:http://www.ituring.com.cn/article/128439 Windows下的PHP开发环境搭建——PHP线程安全与非线程安全.Apache版本选择,及详解五种运行模 ...
- (转)PHP线程安全与非线程安全的区别:如何选择用哪一个?
PHP线程安全与非线程安全的区别:如何选择用哪一个? 很多时候,我们在做PHP环境配置的时候,很多人都是直接去乱下载PHP版本的,但是他不清楚:从2000年10月20日发布的第一个Windows版的P ...
- 浅谈Java中静态初始化块跟非初始化块
众所周知在JAVA编程语言中有两种初始化块: 静态初始化块 非静态初始化块 他们到底有什么区别呢?今天就浅谈一下JAVA中静态初始化块和非静态初始化块的区别 静态初始化块 定义: ...
- Java中的参数验证(非Spring版)
1. Java中的参数验证(非Spring版) 1.1. 前言 为什么我总遇到这种非正常问题,我们知道很多时候我们的参数校验都是放在controller层的传入参数进行校验,我们常用的校验方式就是引入 ...
- java中线程安全和非线程安全的集合
线程安全 非线程安全 Collection Vector ArrayList.LinkedList HashSet.TreeSet Map HashTable HashMap.TreeMap 字符串 ...
随机推荐
- merge和rebase
git里面对于分支的合并处理其实有两种.合并与分基. 对于合并,非常简单.git merge [branch-name] 表示把目标分支合并进当前所在分支 至于分基,简单地讲就是换根.具体细节就不 ...
- Android Studio新建类头部注释和添加函数注释模板及快捷键
一,Android Studio新建类头部注释 是不是有时候看到这个很心烦 其实Studio中有设置修改这些注释模板的信息的功能 其实很简单,只需要两步: 1.打开Setting设置面板,找到File ...
- poj1338【丑数·DP】
我记得这道题以前写过,而且是写出来了.DP吧. 然后现在想了好久...没想出来.... 然后考虑一下递推..mdzz-直接就是让之前的这个每次乘以2,3,5就好了嘛,然后每轮取最小. //#inclu ...
- 我人生中的第一场Java面试
1.说起我的第一次Java面试,我不禁回想起我大学时参加校园招聘的那段日子,那时候我还是本科生,由于不是科班出身,只学过一点点Java皮毛,所以那时候对于找Java工作并没有什么概念,只是以为上过Ja ...
- matplotlib 绘图实例01:正弦余弦曲线
该讲的实例结果如下图所示: 第01步:导入模块,并设置显示中文和负号的属性: import matplotlib.pyplot as plt import numpy as np plt.rcPara ...
- Oracle 十大SQL语句
oracle数据库十大SQL语句 操作对象(object) /*创建对象 table,view,procedure,trigger*/ create object object ...
- 4. iOS测试常用方法
1. [XCUIElement exists]方法只能确定这个View是否存在,即使不在当前屏幕上也返回True.如果要确定View是否在屏幕可见范围内,可以判断其Frame是否在Window的 ...
- 你有学习者综合征吗?Web 开发是重灾区
[导读]:学习者综合征的主要表现:学而不用,不停学习,却没有真正实际应用知识来做东西.如果过去的一年里,学习的语言或框架超过三个,那可能已经感染学习者综合征了.Web 开发是重灾区咯. 你有学习者综合 ...
- 毕业设计:HomeFragment(一)
一.主要思路 主要是通过ListView实现. 考虑到以后会添加长按修改功能,所以好几个地方都是用的FramLayout,而且CheckBox初始状态是被隐藏的.给ListView添加OnItemCl ...
- Android利用已有控件实现自定义控件
Android控件的基本介绍及使用自定义控件的意义 Android 本身提供了很多控件,自定义控件在android中被广泛运用,自定义控件给了我们很大的方便.比如说,一个视图为imag ...