Synchronized 浅析
来源:互联网 发布:60cj数据库 副手 编辑:程序博客网 时间:2024/05/16 23:48
本文目录
1 应用情景
2 同步(Synchronized)
3 原子性
4 锁
5 相关内容
1 应用情景
若多个线程,执行各自的任务操作,互不干扰,则不会出现问题。
但是,若多个线程,在某个阶段或操作中,需要处理同一个共享的数据,就会存在并发问题。
例如:当某个线程正在处理某个数据,另一个进程,也开始对这个数据进行处理(或修改),这样,就可能导致数据错误。
为了避免这种情况的发生,我们可以在线程操作同一个共享数据的地方,进行同步限制。
要求,同一时间,只有获得同步锁(执行权)的线程可以对该共享数据进行操作,其它线程必须等待。
例如:在排队过安检的时候,可能有多个排,但是,到了安检口的时候,只能一个一个的通过。
2 同步(Synchronized)
在Java中,可以通过Synchronized来指定,哪个部分需要进行同步限制。
Synchronized标记的部分,在同一时间,只允许获得同步锁(执行权)的线程来执行这部分的代码,其它线程必须等待。
2.1 同步块(Synchronized Block)
通过synchronized对某一部分代码进行同步限制,代码示例如下:
synchronized(Object obj) { // 同步限制的代码}
表示在大括号内部的代码,在同一时间,只允许获得同步锁(执行权)的线程执行。
其中,obj参数表示同步锁,任何线程必须获得同步锁,然后才可以执行该部分代码。而同步锁只要一个,即同一时间,只有一个线程可以获得该同步锁,因此,保证了同一时间内,只有一个线程可以执行该部分代码。当线程执行完这部分代码后,将同步锁释放。
类比情景:一个仓库,只有一张门锁卡,任何想进入仓库的人,需要先获得门锁卡,然后才能进入仓库(此时,门锁卡随身携带),出仓库后,将门锁卡归还。任何人来到仓库时,都需要先检查门锁卡是否已经被其它人拿走。若已经被其它人拿走,就需要等待,直到那个人把门锁卡归还。
2.2 同步方法(Synchronized Method)
通过synchronized标记某个方法,表示该方法是同步方法,代码示例如下:
public synchronized int count() { // 同步限制的代码}
等效代码如下,即使用当前对象this作为同步锁:
public int count() { synchronized (this) { // 同步限制的代码 }}
由于同步方法都是使用this作为同步锁,由此可以得出,同一个对象里的所有同步方法共用一个同步锁,即同一时间内,只有一个线程(获得同步锁的线程)可以执行这些同步方法。
同理可知,对于同一个类的多个对象(实例),同步机制互不干扰,因为每个对象都是使用自身(this)作为同步锁。
若希望在同一个类的所有对象(实例)实现同步限制,则需要定义一个静态全局变量作为同步锁。
3 原子性
在使用同步机制的时候,我们经常会想到一个问题 —— “某些操作很简单,很快就执行完,是否还需要加锁?”
这个问题的答案在于 “该操作是否为原子性操作” 。
在Java中,只有少部分操作是原子性操作,例如:
num = 1;
某些操作,看似原子性,实则不然,例如:
num++; // 相当于 num = num + 1;num += 1; // 相当于 num = num + 1;
在低并发量的情况下(非压力测试时),类似于 "num++;" 的操作,可能不会发生异常情况(因为几率太小)。
但当处于高并发量的情况时,问题就会暴漏出来。
因此,在对于共享数据进行任何操作时,都需要认真思考是否需要加锁,需要把锁加在哪里?
4 锁
4.1 基本概念
为了实现多线程的同步机制,会在同步限制的部分设置一个锁。
第一个执行到同步限制代码的线程,会获得这个锁,然后,该线程开始执行这部分代码。
此时,若其它线程也执行到这部分代码,发现锁已经被其它线程获取,则开始等待。
当第一个线程执行完这部分代码后,或者主动释放锁,正在等待的其它线程,开始争夺这个锁,得到锁的那一个线程,会开始执行这部分代码,其它线程继续等待。
这样,就保证了,在同一时间,同步限制的代码只被一个线程执行。
4.2 释放锁
obj.wait()
释放锁,并进入暂停状态,直到通过obj.notify/notifyAll被唤醒。
obj.wait(long timeout)
释放锁,并进入暂停状态一段时间后被唤醒,暂停期间也可以通过obj.notify/notifyAll被提前唤醒。
Thread.sleep 与 obj.wait 的区别:
正在执行同步限制代码的线程,若调用Thread.sleep方法,将会暂停执行一段时间,然后,继续执行。暂停的这段时间,该线程依然持有锁,其它线程依然处于等待中。
若该线程调用obj.wait方法,将会释放锁,然后处于暂停状态,直到被唤醒。
由于二者都会使线程暂停,因此,常常被混淆。但实际上,二者是不同领域的概念,一个是线程操作,一个是锁操作。
4.3 激活线程
obj.notify()
随机激活一个处于暂停状态的线程。
obj.notifyAll()
激活所有处于暂停状态的线程。
注意1:obj1.notify/notifyAll 与 obj2.notify/notifyAll 激活的是不同线程。obj1.notify/notifyAll 激活的是通过 obj1.wait 方法处于暂停状态的线程,而obj2.notify/notifyAll 激活的是通过 obj2.wait 方法处于暂停状态的线程。
注意2:被激活的线程,并不是马上恢复执行,而是同其它等待状态中的线程一样,需要等待拥有锁的线程释放锁,然后,开始争夺锁。
4.4 注意事项
obj.wait(), obj.notify(), obj.notifyAll()三个方法都需要在synchronized方法或synchronized块中使用,即获得了某锁(obj)后,才能对该锁进行相关的操作。
5 相关内容
5.1 java.util.concurrent.Semaphore
Semaphore被译为信号量,这里姑且也当成锁来看待,为便于理解。
在创建 Semaphore 对象的时候,可以指定锁的数量,代码如下:
Semaphore semaphore = new Semaphore(3);
每次调用semaphore.acquire()获得一个锁时,可用锁的数量减一;每次调用semaphore.release()释放一个锁时,可用锁的数量加一。
当可用锁的数量为0时,semaphore.acquire()将阻塞当前调用线程,直到其它线程调用semaphore.release()释放了一个锁之后,该线程获得锁并继续执行。
5.2 java.util.concurrent.locks.ReentrantLock
ReentrantLock 与 synchronized 有着相似的作用,但内部原理却不尽相同。从功能上来看, ReentrantLock 功能更为强大些,但使用起来会相对复杂一些。
ReentrantLock 对象通过 lock() 和 unlock() 进行加锁与解锁操作,需要注意的是,unlock()通常放在finally块中执行,以保证锁最终一定会被释放,代码如下:
ReentrantLock reentrantlock = new ReentrantLock();reentrantlock.lock();try { // 代码} finally { reentrantlock.unlock();}
公平锁:多个线程竞争同一个锁时,若希望按照申请锁的顺序来依次获得锁,则需要通过构造方法参数指定,代码如下:
ReentrantLock reentrantlock = new ReentrantLock(boolean fair);
设置等待时间:当申请一个锁时,可以指定等待时间,若该锁已被其它线程获取,且一直不释放,到达指定时间后,将放弃申请该锁,代码如下:
reentrantlock.tryLock(long timeout, TimeUnit unit);
5.3 集合的同步机制
在Java中,List、Set和Map也可以实现synchronized的功能,使其相关操作具有synchronized特性。
List<string> list = Collections.synchronizedList(new ArrayList<string>()); Set<string> set = Collections.synchronizedSet(new HashSet<string>()); Map<Integer, string> map = Collections.synchronizedMap(new HashMap<Integer, string>());
通过Collections.synchronizedXxxx方法,使标准集合对象具有synchronized特性,所有同步方法共用同一个锁,从而,使这些对象的增删改查等方法,在同一时间,只允许一个线程调用。
- synchronized浅析
- Synchronized 浅析
- synchronized浅析
- 浅析synchronized关键字
- android synchronized浅析
- java synchronized浅析
- synchronized原理浅析
- synchronized和ReentrantLock区别浅析
- synchronized和lock比较浅析
- synchronized和lock比较浅析
- synchronized和lock比较浅析
- synchronized和lock比较浅析
- synchronized和ReentrantLock区别浅析
- 浅析java多线程之Synchronized关键字
- 【Java】Synchronized和Lock比较浅析
- java多线程:synchronized和lock比较浅析
- 浅析Java多线程synchronized关键字、wait和notify方法
- Java 锁机机制——浅析 Synchronized
- C++数组,字符串,string,结构,共用体,枚举,指针,静态动态内存,vector及array类简介
- JAVA中的四种Reference
- android开源项目view篇
- Android开发:该视频无法播放
- Spoj Query on a tree SPOJ - QTREE(树链剖分+线段树)
- Synchronized 浅析
- POJ 2456 Aggressive cows(二分查找最大化最小值)
- Hadoop----集群搭建指南(中卷)
- struts2上传文件(Common-FileUpload)
- JDBC
- notepade++在许多种语言下的使用方法
- 超星中职生课程 职业生涯规划 于丽答案题库
- 学编程为什么这么难?每个新手绝对要知道的那些事
- hexo] Light主题的修改使用