[Java并发]-02-同步和锁
来源:互联网 发布:知悉和悉知的区别 编辑:程序博客网 时间:2024/05/29 18:28
2 同步
2.1 同步问题
临界区:用以访问共享资源的代码块,这个代码块同一时间内只允许一个线程执行。
同步就是为了防止多个线程进入临界区。
当一个线程试图访问临界区的时候,它将使用一种同步机制来查看是不是已经又其他线程进入临界区,如果没有其它线程进入临界区,它就可以进入临界区。如果有线程已经进入临界区它就被线程机制挂起,直到进入的线程离开临界区,如果有等待的线程不止有一个,JVM会选择一个运行,其余的线程继续等待。
两种同步机制
- synchronized关键字机制
- Lock接口及其实现机制
static class Counter {private int count;public Counter(int count) {init(count);}public void init(int count) {this.count = count;}public void add() {this.count++;}public void subtraction() {if (this.count > 0) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}this.count--;System.out.println("subtraction " + count);}}public int getCount() {return this.count;}}public static void main(String[] args) {System.out.println("=========main start");final Counter counter = new Counter(10);new Thread() {@Overridepublic void run() {for (int i = 0 ; i < 100; i++) {counter.subtraction();}System.out.println("run1 " + counter.getCount());}}.start();new Thread() {@Overridepublic void run() {for (int i = 0 ; i < 100; i++) {counter.subtraction();}System.out.println("run2 " + counter.getCount());}}.start();System.out.println("=========main end");}
=========main start
=========main end
subtraction 9
subtraction 8
subtraction 7
subtraction 6
subtraction 5
subtraction 4
subtraction 3
subtraction 2
subtraction 1
subtraction 0
run2 0
subtraction -1
run1 -1
发生这种现象的原因是:当counter是1的时候,第一个线程进入subtraction方法,运行到sleep处让出CPU,这时第二个线程也运行到这个方法,进行if判断时候counter仍然是1,进入if块后也sleep,这时两个线程都进入到subtraction方法的sleep处等待,进入前判断大于0的条件都是true;
此时一个线程完成sleep counter--,另一个线程也完成sleep有counter--这样就是-1了
只要将
public synchronized void subtraction()
结果就会不一样了
=========main start
=========main end
subtraction 9
subtraction 8
subtraction 7
subtraction 6
subtraction 5
subtraction 4
subtraction 3
subtraction 2
subtraction 1
subtraction 0
run2 0
run1 0
2.2 synchronized
Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
原理:synchronized是有参数的,参数是一个对象,当一个线程执行到synchronized语句时候,JVM会先检查这个参数对象是不是被别的线程占用,如果没有被占用则占用之。
这个参数被称为锁对象,线程获得synchronized的锁对象后,其他针对这个锁对象的synchronized块全都被锁,其他线程若想进入则必须获得该锁对象。
锁的释放
1.线程执行完了当前synchronized块
2.锁对象调用wait()
2.3 Object对象的方法wait() notify() notifyAll()
Obj.wait(),与Obj.notify()必须要与synchronized(Obj)一起使用,也就是wait,与notify是针对已经获取了Obj锁进行操作,从语法角度来说就是Obj.wait(),Obj.notify必须在synchronized(Obj){...}语句块内。
wait就是说线程在获取对象锁后,主动释放对象锁,同时本线程休眠。
直到有其它线程调用对象的notify()唤醒该线程,才能继续获取对象锁,并继续执行。
Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制。
会降低程序的性能,因此尽量让临界区合理的尽可能的最小。
synchronized针对的是对象进行的同步,非静态方法 同步锁对象是this
静态方法的同步锁对象是类的class对象
可以通过非依赖属性,进行多个同步,多个同步锁之间不影响
注意: 方法的synchronized是不继承的!
如果再同步代码块外使用wait()等 JVM会抛出IllegalMonitorStateException
当一个线程调用wait()方法时候JVM将这个线程置入休眠,并且释放控制这个同步代码块的锁对象,同时允许其它线程执行这个对象控制的其它同步代码块。
为了唤醒这个线程,需要在这个锁对象控制的同步代码块中调用notify()或notifyAll()
private byte[] lock = new byte[0];
注:零长度的byte数组对象创建起来将比任何对象都经济。查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。可以作为同步锁对象
2.4wait()
下面是一个synchronized 同步方法和wait()的demo
public class EventStorage {private int maxSize;private LinkedList<Date> storage;/** * */public EventStorage() {super();this.maxSize = 500;this.storage = new LinkedList<Date>();}public synchronized void set() {while(storage.size() == maxSize) {try {wait();} catch(InterruptedException e) {e.printStackTrace();}}storage.add(new Date());System.out.printf("Set: %d\n", storage.size());notifyAll();}public synchronized void get() {while(storage.size() == 0) {try {wait();} catch(InterruptedException e) {e.printStackTrace();}}System.out.printf("Get: %d, %s\n", storage.size(), storage.poll());notifyAll();}}public class Producer implements Runnable {private EventStorage storage;public Producer(EventStorage storage) {this.storage = storage;}/* * (non-Javadoc) * * @see java.lang.Runnable#run() */@Overridepublic void run() {for (int i = 0; i < 1000; i++) {storage.set();}}}public class Consumer implements Runnable {private EventStorage storage;public Consumer(EventStorage storage) {this.storage = storage;}/* (non-Javadoc) * @see java.lang.Runnable#run() */@Overridepublic void run() {for (int i = 0; i < 1000; i++) {storage.get();}}}
public static void main(String[] args) {EventStorage storage = new EventStorage();new Thread(new Producer(storage)).start();new Thread(new Consumer(storage)).start();}
可以看看输出理解一下
调用wait()的对象也是synchronized的方法中隐含的同步锁对象 this
然后改改,用一个Object对象作为锁对象
public class EventStorage {private int maxSize;private LinkedList<Date> storage;private Object lock = new Object();/** * */public EventStorage() {super();this.maxSize = 500;this.storage = new LinkedList<Date>();}public void set() {synchronized (lock) {while (storage.size() == maxSize) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}storage.add(new Date());System.out.printf("Set: %d\n", storage.size());lock.notifyAll();}}public void get() {synchronized (lock) {while (storage.size() == 0) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.printf("Get: %d, %s\n", storage.size(), storage.poll());lock.notifyAll();}}}
为了说明问题 再继续改
public class EventStorage {private int maxSize;private LinkedList<Date> storage;private Object lock = new Object();public EventStorage() {super();this.maxSize = 2;this.storage = new LinkedList<Date>();}public void set() {synchronized (lock) {while (storage.size() == maxSize) {System.out.println("set while start = " + storage.size());try {System.out.println("set lock.wait() start");lock.wait();// 让获得该锁的当前线程进入等待队列System.out.println("set lock.wait() end");} catch (InterruptedException e) {e.printStackTrace();}System.out.println("set while end = " + storage.size());}storage.add(new Date());System.out.printf("Set: %d\n", storage.size());System.out.println("set lock.notifyAll() start");lock.notifyAll();// 告知该锁的等待队列中的线程System.out.println("set lock.notifyAll() end");}}public void get() {synchronized (lock) {while (storage.size() == 0) {System.out.println("get while start = " + storage.size());try {System.out.println("get lock.wait() start");lock.wait();// 让获得该锁的当前线程进入等待队列System.out.println("get lock.wait() end");} catch (InterruptedException e) {e.printStackTrace();}System.out.println("get while end = " + storage.size());}System.out.printf("Get: %d, %s\n", storage.size(), storage.poll());System.out.println("get lock.notifyAll() start");lock.notifyAll();// 告知该锁的等待队列中的线程,可以来获得CPUSystem.out.println("get lock.notifyAll() end");}}}public class Producer implements Runnable {private EventStorage storage;public Producer(EventStorage storage) {this.storage = storage;}@Overridepublic void run() {for (int i = 0; i < 10; i++) {storage.set();}}}public class Consumer implements Runnable {private EventStorage storage;public Consumer(EventStorage storage) {this.storage = storage;}@Overridepublic void run() {for (int i = 0; i < 10; i++) {storage.get();}}}
public static void main(String[] args) {EventStorage storage = new EventStorage();Thread producer = new Thread(new Producer(storage));Thread consumer = new Thread(new Consumer(storage));producer.start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}consumer.start();}
Set: 1
set lock.notifyAll() start
set lock.notifyAll() end
Set: 2
set lock.notifyAll() start
set lock.notifyAll() end
set while start = 2
set lock.wait() start
Get: 2, Mon Nov 17 09:11:55 CST 2014
get lock.notifyAll() start
get lock.notifyAll() end
Get: 1, Mon Nov 17 09:11:55 CST 2014
get lock.notifyAll() start
get lock.notifyAll() end
get while start = 0
get lock.wait() start
set lock.wait() end
set while end = 0
Set: 1
set lock.notifyAll() start
set lock.notifyAll() end
Set: 2
set lock.notifyAll() start
set lock.notifyAll() end
set while start = 2
set lock.wait() start
get lock.wait() end
get while end = 2
Get: 2, Mon Nov 17 09:11:56 CST 2014
get lock.notifyAll() start
get lock.notifyAll() end
Get: 1, Mon Nov 17 09:11:56 CST 2014
get lock.notifyAll() start
get lock.notifyAll() end
get while start = 0
get lock.wait() start
set lock.wait() end
set while end = 0
Set: 1
set lock.notifyAll() start
set lock.notifyAll() end
Set: 2
set lock.notifyAll() start
set lock.notifyAll() end
set while start = 2
set lock.wait() start
get lock.wait() end
get while end = 2
Get: 2, Mon Nov 17 09:11:56 CST 2014
get lock.notifyAll() start
get lock.notifyAll() end
Get: 1, Mon Nov 17 09:11:56 CST 2014
get lock.notifyAll() start
get lock.notifyAll() end
get while start = 0
get lock.wait() start
set lock.wait() end
set while end = 0
Set: 1
set lock.notifyAll() start
set lock.notifyAll() end
Set: 2
set lock.notifyAll() start
set lock.notifyAll() end
set while start = 2
set lock.wait() start
get lock.wait() end
get while end = 2
Get: 2, Mon Nov 17 09:11:56 CST 2014
get lock.notifyAll() start
get lock.notifyAll() end
Get: 1, Mon Nov 17 09:11:56 CST 2014
get lock.notifyAll() start
get lock.notifyAll() end
get while start = 0
get lock.wait() start
set lock.wait() end
set while end = 0
Set: 1
set lock.notifyAll() start
set lock.notifyAll() end
Set: 2
set lock.notifyAll() start
set lock.notifyAll() end
get lock.wait() end
get while end = 2
Get: 2, Mon Nov 17 09:11:56 CST 2014
get lock.notifyAll() start
get lock.notifyAll() end
Get: 1, Mon Nov 17 09:11:56 CST 2014
get lock.notifyAll() start
get lock.notifyAll() end
可见wait会让线程就在wait调用处等待,并且释放锁。
sleep只是等待,不会释放同步锁。
2.5 锁
锁是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问。
一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁。
不过,某些锁可能允许对共享资源并发访问,如ReadWriteLock的读取锁。
2.6 使用 Lock的Demo
先看看Lock怎么用, 先用synchronized实现一个打印队列
public class PrintQueue { public PrintQueue() {} public synchronized void printJob(Object doc) { long duration = (long)(Math.random() * 10000); System.out.println(Thread.currentThread().getName() + " : start print " + (duration / 1000) +" secs"); try { Thread.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " : print completed"); }}static class Job implements Runnable {private PrintQueue queue;public Job(PrintQueue queue) {this.queue = queue;}@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " run start");queue.printJob(new Object());System.out.println(Thread.currentThread().getName() + " run end");}}public static void main(String[] args) {PrintQueue queue = new PrintQueue();for (int i = 0; i < 10; i++) {new Thread(new Job(queue)).start();}}}
Thread-0 run start
Thread-1 run start
Thread-2 run start
Thread-0 : start print 7 secs
Thread-3 run start
Thread-4 run start
Thread-5 run start
Thread-6 run start
Thread-7 run start
Thread-8 run start
Thread-9 run start
Thread-0 : print completed
Thread-0 run end
Thread-9 : start print 9 secs
Thread-9 : print completed
Thread-9 run end
Thread-8 : start print 1 secs
Thread-8 : print completed
Thread-8 run end
Thread-7 : start print 9 secs
Thread-7 : print completed
Thread-7 run end
Thread-6 : start print 8 secs
Thread-6 : print completed
Thread-6 run end
Thread-5 : start print 9 secs
Thread-5 : print completed
Thread-5 run end
Thread-4 : start print 1 secs
Thread-4 : print completed
Thread-4 run end
Thread-3 : start print 7 secs
Thread-3 : print completed
Thread-3 run end
Thread-2 : start print 9 secs
Thread-2 : print completed
Thread-2 run end
Thread-1 : start print 5 secs
Thread-1 : print completed
Thread-1 run end
然后试试Lock同步的方式
public void printJob(Object doc) {queueLock.lock();System.out.println("queueLock.lock()");long duration = (long) (Math.random() * 10000 );System.out.println(Thread.currentThread().getName() + " : start print " + (duration / 1000) + " secs");try {Thread.sleep(duration);} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println("queueLock.unlock()");queueLock.unlock();}System.out.println(Thread.currentThread().getName() + " : print completed");}
2.7 Lock的继承关系
重入锁(ReentrantLock)是一种递归无阻塞的同步机制。
http://tenyears.iteye.com/blog/48750
Reentrant [rɪ'entrənt]
2.8 使用ReentrantReadWriteLock
这个类有两个锁一个是读锁,一个是写锁,读操作可以多线程同时访问,但是写操作时只允许一个线程进行。在写操作进行时,其它线程不能进行读操作。
public class PricesInfo {private int price1;private int price2;private ReadWriteLock rwLock = null;public PricesInfo() {price1 = 1;price2 = 2;rwLock = new ReentrantReadWriteLock();}public int getPrice1() {rwLock.readLock().lock();System.out.println(Thread.currentThread().getName()+ "get start price1");int temp = price1;try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+ "get end price1=" + price1);rwLock.readLock().unlock();return temp;}public int getPrice2() {rwLock.readLock().lock();System.out.println(Thread.currentThread().getName()+ "get start price2");int temp = price2;try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+ "get end price2=" + price2);rwLock.readLock().unlock();return temp;}public void setPrices(int p1, int p2) {rwLock.writeLock().lock();System.out.println(Thread.currentThread().getName() + " set prices start");price1 = p1;price2 = p2;System.out.println(Thread.currentThread().getName() + " set price1=" + price1 + " price2=" + price2);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " set prices end");rwLock.writeLock().unlock();}static class Reader implements Runnable {private PricesInfo prices;public Reader(PricesInfo prices) {this.prices = prices;}@Overridepublic void run() {for (int i = 0; i < 10; i++) {prices.getPrice1();prices.getPrice2();}}}static class Writer implements Runnable {private PricesInfo prices;public Writer(PricesInfo prices) {this.prices = prices;}@Overridepublic void run() {for (int i = 0; i < 3; i++) {this.prices.setPrices((int)(Math.random() * 10),(int)(Math.random() * 10));}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {PricesInfo prices = new PricesInfo();for (int i = 0; i < 10; i++) {new Thread(new Reader(prices)).start();}for (int i = 0; i < 2; i++) {new Thread(new Writer(prices)).start();}}}Thread-0get start price1
Thread-2get start price1
Thread-1get start price1
Thread-3get start price1
Thread-4get start price1
Thread-5get start price1
Thread-6get start price1
Thread-7get start price1
Thread-8get start price1
Thread-9get start price1
Thread-1get end price1=1
Thread-4get end price1=1
Thread-7get end price1=1
Thread-0get end price1=1
Thread-2get end price1=1
Thread-8get end price1=1
Thread-3get end price1=1
Thread-9get end price1=1
Thread-5get end price1=1
Thread-6get end price1=1
Thread-10 set prices start
Thread-10 set price1=3 price2=1
Thread-10 set prices end
Thread-11 set prices start
Thread-11 set price1=3 price2=2
Thread-11 set prices end
Thread-4get start price2
Thread-7get start price2
Thread-1get start price2
Thread-2get start price2
Thread-0get start price2
Thread-5get start price2
Thread-9get start price2
Thread-3get start price2
Thread-8get start price2
Thread-6get start price2
Thread-1get end price2=2
Thread-2get end price2=2
Thread-4get end price2=2
Thread-0get end price2=2
Thread-8get end price2=2
Thread-3get end price2=2
Thread-7get end price2=2
Thread-6get end price2=2
Thread-9get end price2=2
Thread-5get end price2=2
Thread-10 set prices start
Thread-10 set price1=9 price2=3
Thread-10 set prices end
Thread-10 set prices start
Thread-10 set price1=4 price2=9
Thread-10 set prices end
Thread-11 set prices start
Thread-11 set price1=9 price2=8
Thread-11 set prices end
Thread-1get start price1
Thread-2get start price1
Thread-4get start price1
Thread-0get start price1
Thread-8get start price1
Thread-3get start price1
Thread-6get start price1
Thread-7get start price1
Thread-5get start price1
Thread-9get start price1
Thread-4get end price1=9
Thread-9get end price1=9
Thread-8get end price1=9
Thread-2get end price1=9
Thread-0get end price1=9
Thread-7get end price1=9
Thread-6get end price1=9
Thread-5get end price1=9
Thread-3get end price1=9
Thread-1get end price1=9
Thread-11 set prices start
Thread-11 set price1=8 price2=2
Thread-11 set prices end
Thread-4get start price2
Thread-9get start price2
Thread-2get start price2
Thread-8get start price2
Thread-3get start price2
Thread-5get start price2
Thread-6get start price2
Thread-7get start price2
Thread-0get start price2
2.9 tryLock
2.10 修改锁的公平性 fairness
ReentrantLock和ReetrantReadWriteLock构造函数都含有一个boolean参数 fair,默认是false的,称为非公平模式
如果传入fair为true,则为公平模式,当很多线程等待锁(ReentrantLock或ReetrantReadWriteLock)时,锁将选择他们中等待时间最长的那个来访问临界区。
只针对lock和unlock方法,tryLock没有将线程休眠,fair不影响这个方法
public class PrintQueue {private final Lock queueLock = new ReentrantLock(true); // 传入fair 为truepublic PrintQueue() {}public void printJob(Object doc) {queueLock.lock();System.out.println(Thread.currentThread().getName() + " run start queueLock.lock()");long duration = (long) (Math.random() * 10000 / 2);System.out.println(Thread.currentThread().getName() + " : start print " + (duration / 1000) + " secs");try {Thread.sleep(duration);} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println(Thread.currentThread().getName() + "queueLock.unlock()");queueLock.unlock();}System.out.println(Thread.currentThread().getName() + " : print completed.");}static class Job implements Runnable {private PrintQueue queue;public Job(PrintQueue queue) {this.queue = queue;}@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " run start");queue.printJob(new Object());}}public static void main(String[] args) {PrintQueue queue = new PrintQueue();for (int i = 0; i < 10; i++) {new Thread(new Job(queue)).start();}}}
Thread-0 run start
Thread-2 run start
Thread-1 run start
Thread-0 run start queueLock.lock()
Thread-3 run start
Thread-0 : start print 0 secs
Thread-4 run start
Thread-5 run start
Thread-6 run start
Thread-7 run start
Thread-8 run start
Thread-9 run start
Thread-0queueLock.unlock()
Thread-0 : print completed.
Thread-2 run start queueLock.lock()
Thread-2 : start print 2 secs
Thread-2queueLock.unlock()
Thread-2 : print completed.
Thread-1 run start queueLock.lock()
Thread-1 : start print 4 secs
Thread-1queueLock.unlock()
Thread-1 : print completed.
Thread-3 run start queueLock.lock()
Thread-3 : start print 3 secs
Thread-3queueLock.unlock()
Thread-3 : print completed.
Thread-4 run start queueLock.lock()
Thread-4 : start print 3 secs
Thread-4queueLock.unlock()
Thread-5 run start queueLock.lock()
Thread-5 : start print 3 secs
Thread-4 : print completed.
Thread-5queueLock.unlock()
Thread-5 : print completed.
Thread-6 run start queueLock.lock()
Thread-6 : start print 4 secs
Thread-6queueLock.unlock()
Thread-6 : print completed.
Thread-7 run start queueLock.lock()
Thread-7 : start print 4 secs
Thread-7queueLock.unlock()
Thread-7 : print completed.
Thread-8 run start queueLock.lock()
Thread-8 : start print 4 secs
Thread-8queueLock.unlock()
Thread-8 : print completed.
Thread-9 run start queueLock.lock()
Thread-9 : start print 1 secs
Thread-9queueLock.unlock()
Thread-9 : print completed.
根据结果会发现,thread0获得锁后,先start的线程会先获得锁。
2.11 在锁中使用多条件
Condition接口提供了挂起线程和唤醒线程的机制。类似于wait notify 和notifyAll。
问题产生于,当Lock替代了synchronized时候 锁对象的wait() notify() notifyAll()用什么替代呢?引入了 Condition来进行锁对象(Lock或ReadWriteLock)等待和通知操作
不能重名 所以Condition对象 用await() signal() signalAll()来处理代替Object对象的wait() notify() notifyAll()
Condition对象不能代替判断条件,条件仍需要再循环中判断 当不满足时候 继续await
long awaitNanos(long nanosTimeout) throws InterruptedException; boolean await(long time, TimeUnit unit) throws InterruptedException; 某个线程中断当前线程 其他某个线程调用了当前线程挂起的条件singal()和singnalAll()方法 制定等待时间过去 boolean awaitUntil(Date deadline) throws InterruptedException;某个线程中断当前线程其他某个线程调用了当前线程挂起的条件singal()和singnalAll()方法制定等待时间到了void awaitUninterruptibly();不可中断的,这线程将休眠直到其他某个线程调用了将它挂起条件的signal 或signalAll
Condition对象要通过Lock#newCondition()创建,才是相关锁的条件.而且Condition对象使用的代码,必须再相关联的Lock对象的lock()和unlock() 之间。
也可以将Condition对象和ReadLock和WriteLock一起使用,ReadLock和WriteLock也是继承自Lock接口
2.1.1 Lock和synchronized的对比
synchronized
方法或语句的使用提供了对与每个对象相关的隐式监视器锁的访问,但却强制所有锁获取和释放均要出现在一个块结构中:当获取了多个锁时,它们必须以相反的顺序释放,且必须在与所有锁被获取时相同的词法范围内释放所有锁。
某些遍历并发访问的数据结果的算法要求使用 "hand-over-hand" 或 "chain locking":获取节点 A 的锁,然后再获取节点 B 的锁,然后释放 A 并获取 C,然后释放 B 并获取 D,依此类推。Lock
接口的实现允许锁在不同的作用范围内获取和释放,并允许以任何顺序获取和释放多个锁
随着灵活性的增加,也带来了更多的责任。不使用块结构锁就失去了使用 synchronized
方法和语句时会出现的锁自动释放功能。在大多数情况下,应该使用以下语句:
Lock l = ...; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }锁定和取消锁定出现在不同作用范围中时,必须谨慎地确保保持锁定时所执行的所有代码用 try-finally 或 try-catch 加以保护,以确保在必要时释放锁。
Lock
实现提供了使用 synchronized
方法和语句所没有的其他功能,包括提供了一个非块结构的获取锁尝试 (tryLock()
)、一个获取可中断锁的尝试 (lockInterruptibly()
) 和一个获取超时失效锁的尝试 (tryLock(long, TimeUnit)
)。
Lock
类还可以提供与隐式监视器锁完全不同的行为和语义,如保证排序、非重入用法或死锁检测。如果某个实现提供了这样特殊的语义,则该实现必须对这些语义加以记录。
Lock
实例只是普通的对象,其本身可以在 synchronized
语句中作为目标使用。获取 Lock
实例的监视器锁与调用该实例的任何 lock()
方法没有特别的关系。为了避免混淆,建议除了在其自身的实现中之外,决不要以这种方式使用Lock
实例。synchronized
在离开块的时候自动放锁,其顺序没法控制,Lock需要自己控制放锁,可以按照任意顺序。- Lock允许更复杂的临界区?使用更灵活
- Lock可以分离读写操作,允许多个线程读和只有一个线程写
- Lock接口又更好的性能
- Lock有tryLock方法如果,试图获取锁如果锁没有被占则获取之,如果锁被占则返回false继续执行下面的代码,不使线程等待。
- Lock使用的时候逻辑上清晰明确
tryLock要求开发人员出主意关注返回false时候,不要执行临界区代码。
ReentrantLock运行递归调用,将继续持有锁,lock方法立即返回
要十分小心使用锁,避免死锁
2.5 Thread状态 死锁理论
- [Java并发]-02-同步和锁
- 【Java并发编程】内在锁和同步
- JAVA并发-同步容器和并发容器
- java并发编程(synchronized同步和Lock显示锁)
- Java并发编程---对象锁的同步和异步
- Java---并发和同步(生产者--消费者)
- java中的同步容器和并发容器
- Java同步容器和并发容器
- Java的同步容器和并发容器
- JavaSE:Java多线程并发和线程同步
- Java 8并发教程:同步和锁定
- Java并发:线程安全的容器:同步和并发
- Java并发编程:同步容器、并发容器和阻塞队列
- Java 8 并发之同步与锁
- Java并发与同步
- java并发代码同步
- java-并发-同步容器
- Java并发、同步总结
- chmod g+s 、chmod o+t 、chmod u+s
- 第十二周项目一(2)
- 博客搬家算法伪码
- POJ 2739 Sum of Consecutive Prime Numbers(素数)
- 基于BroadCastSend的短信转发
- [Java并发]-02-同步和锁
- C#+IM+agsXMPP
- How to Get Source Code of a Linux Command on CentOS
- 利用互斥对象实现线程同步
- 痛苦,就是因为我们太弱;从容,就是因为我们变强了
- 使用class-dump-z
- 编写Javascript类库(jQuery版) - 进阶者系列 - 学习者系列文章
- Maven配置maven-eclipse-plugin(mvn eclipse:eclipse报错问题)
- Android开发:性能最佳实践-管理应用内存