一、什么是sychronized
sychronized是java中最基本同步互斥的手段,可以修饰代码块,方法,类.
在修饰代码块的时候需要一个reference对象作为锁的对象.
在修饰方法的时候默认是当前对象作为锁的对象.
在修饰类时候默认是当前类的Class对象作为锁的对象.
synchronized会在进入同步块的前后分别形成monitorenter和monitorexit字节码指令.在执行monitorenter指令时会尝试获取对象的锁,如果此没对象没有被锁,或者此对象已经被当前线程锁住,那么锁的计数器加一,每当monitorexit被锁的对象的计数器减一.直到为0就释放该对象的锁.由此synchronized是可重入的,不会出现自己把自己锁死.
以对象的方式来操作对象锁.相对于sychronized需要在finally中去释放锁。
三、synchronized和ReentrantLock的区别
1. 等待可中断
在持有锁的线程长时间不释放锁的时候,等待的线程可以选择放弃等待. tryLock(long timeout, TimeUnit unit)。
ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候。
线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定。
如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断。
如果使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情。
ReentrantLock获取锁定与三种方式:
a) lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
c) tryLock (long timeout, TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
d) lockInterruptibly: 如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断
2.公平锁与非公平锁
按照申请锁的顺序来一次获得锁称为公平锁.synchronized的是非公平锁,ReentrantLock可以通过构造函数实现公平锁. new RenentrantLock(boolean fair)
3.绑定多个Condition
通过多次newCondition可以获得多个Condition对象,可以简单的实现比较复杂的线程同步的功能.通过await(),signal()
此外,synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将 unLock()放到finally{} 中。在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态。
ReentrantLock 的lock机制有2种,忽略中断锁和响应中断锁,这给我们带来了很大的灵活性。比如:如果A、B两个线程去竞争锁,A线程得到了锁,B线程等待,但是A线程这个时候实在有太多事情要处理,就是一直不返回,B线程可能就会等不及了,想中断自己,不再等待这个锁了,转而处理其他事情。这个时候ReentrantLock就提供了两种机制:
一、B线程中断自己(或者别的线程中断它),但ReentrantLock 不去响应,让B线程继续等待,你再怎么中断,我全当耳边风(synchronized原语就是如此);
二、B线程中断自己(或者别的线程中断它),ReentrantLock 处理了这个中断,并且不再等待这个锁的到来,完全放弃。
请看例子:
[html] view plain copy
- package zmx.multithread.test.reentrantlock;
- import java.util.concurrent.locks.ReentrantLock;
- /**
- *
- * @author zhangwenchao
- *
- */
- public class ReentrantLockTest {
- //是用ReentrantLock,还是用synchronized
- public static boolean useSynchronized = false;
- public static void main(String[] args) {
- IBuffer buff = null;
- if(useSynchronized){
- buff = new Buffer();
- }else{
- buff = new BufferInterruptibly();
- }
- final Writer writer = new Writer(buff);
- final Reader reader = new Reader(buff);
- writer.start();
- reader.start();
- new Thread(new Runnable() {
- public void run() {
- long start = System.currentTimeMillis();
- for (;;) {
- // 等5秒钟去中断读
- if (System.currentTimeMillis() - start > 5000) {
- System.out.println("不等了,尝试中断");
- reader.interrupt();
- break;
- }
- }
- }
- }).start();
- }
- }
- interface IBuffer{
- public void write();
- public void read() throws InterruptedException;
- }
- class Buffer implements IBuffer{
- private Object lock;
- public Buffer() {
- lock = this;
- }
- public void write() {
- synchronized (lock) {
- long startTime = System.currentTimeMillis();
- System.out.println("开始往这个buff写入数据…");
- for (;;)// 模拟要处理很长时间
- {
- if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)
- break;
- }
- System.out.println("终于写完了");
- }
- }
- public void read() {
- synchronized (lock) {
- System.out.println("从这个buff读数据");
- }
- }
- }
- class BufferInterruptibly implements IBuffer{
- private ReentrantLock lock = new ReentrantLock();
- public void write() {
- lock.lock();
- try {
- long startTime = System.currentTimeMillis();
- System.out.println("开始往这个buff写入数据…");
- for (;;)// 模拟要处理很长时间
- {
- if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)
- break;
- }
- System.out.println("终于写完了");
- } finally {
- lock.unlock();
- }
- }
- public void read() throws InterruptedException{
- lock.lockInterruptibly();// 注意这里,可以响应中断
- // lock.lock();// 注意这里,不可以响应中断
- try {
- System.out.println("从这个buff读数据");
- } finally {
- lock.unlock();
- }
- }
- }
- class Writer extends Thread {
- private IBuffer buff;
- public Writer(IBuffer buff) {
- this.buff = buff;
- }
- @Override
- public void run() {
- buff.write();
- }
- }
- class Reader extends Thread {
- private IBuffer buff;
- public Reader(IBuffer buff) {
- this.buff = buff;
- }
- @Override
- public void run() {
- try {
- buff.read();
- } catch (InterruptedException e) {
- System.out.println("我不读了");
- }
- System.out.println("读结束");
- }
- }
1) 如果使用lock.lockInterruptibly();指定可以响应中断,则输出如下:
[html] view plain copy
- 开始往这个buff写入数据…
- 不等了,尝试中断
- 我不读了
- 读结束
则:获取到中断异常,执行中断异常处理程序。
2) 如果使用lock.lock();指定不可以响应中断,则输出如下:
[html] view plain copy
- 开始往这个buff写入数据…
- 不等了,尝试中断
则:不能获取到中断异常,线程等待。
示例二:
[html] view plain copy
- package zmx.multithread.test.reentrantlock;
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- public class T2{
- public static void main(String[] args){
- Thread i1 = new Thread(new RunIt3());
- Thread i2 = new Thread(new RunIt3());
- i1.start();
- i2.start();
- i2.interrupt(); //中断
- }
- }
- class RunIt3 implements Runnable{
- private static Lock lock = new ReentrantLock();
- public void run(){
- try{
- //---------a--------------------------
- //lock.lock();
- lock.lockInterruptibly();
- //lock.tryLock();
- //lock.tryLock(5,TimeUnit.SECONDS);
- System.out.println(Thread.currentThread().getName() + " running");
- TimeUnit.SECONDS.sleep(10);
- System.out.println(Thread.currentThread().getName() + " finished");
- lock.unlock();
- }catch (InterruptedException e){
- System.out.println(Thread.currentThread().getName() + " interrupted");
- }
- }
- }
如果a处是lock.lock(); 输出:
Thread-0 running
(这里休眠了10s)
Thread-0 finished
Thread-1 running
Thread-1 interrupted
============================
如果a处是lock.lockInterruptibly();输出:
Thread-0 running
Thread-1 interrupted
(这里休眠了10s)
Thread-0 finished