程序员人生 网站导航

java Lock和Condition的用法

栏目:综合技术时间:2016-10-05 09:47:00

前面我分享了Synchronized的使用,当1个线程访问1个对象的Synchronized方法或代码块的时候,就持有了锁,除非履行完或遇到异常(产生异常JVM虚拟机会自动释放锁),才能释放锁,但是如果在履行代码块里sleep了或有1些耗时很久的操作,那末锁就1直不释放,其他线程就会1直等待下去,Lock可以不让其他线程1直无穷等待下去,另外1种情况,当有多个线程读写文件的时候,读和写会产生冲突,写和写会产生冲突,读和读按理应当不会产生冲突,但是如果用Synchronized的话,读和读也会产生冲突,ReadWriteLock可以解决这个问题,有1个点需要强调下,Synchronized是java内置语言,Lock不是,当1个线程履行完Synchronized修饰的方法或代码块以后,JVM会自动释放锁,但是Lock不会,必须手动履行lock.unLock()方法来释放锁,否则锁就永久不会得到释放。
1 Lock.lock,代码以下:

import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockTest { public static void main(String args[]) { LockObject lo = new LockObject(); MyThread t1 = new MyThread(lo); MyThread t2 = new MyThread(lo); Thread ta = new Thread(t1,"A"); Thread tb = new Thread(t2,"B"); ta.start(); tb.start(); } } class LockObject { Lock lock = new ReentrantLock(); public void LockFuc() { lock.lock(); try { System.out.println(Thread.currentThread().getName() + "得到了锁"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); System.out.println(Thread.currentThread().getName() + "释放了锁"); } } } class MyThread implements Runnable{ LockObject lo= null; public MyThread(LockObject lo){ this.lo = lo; } @Override public void run() { // TODO Auto-generated method stub lo.LockFuc(); } }

开始调用了lock.lock得到锁,然后同步代码放到try catch中,在finally里履行lock.unlock释放锁,履行结果以下:
A得到了锁
A释放了锁
B得到了锁
B释放了锁

2 lock.tryLock(),代码以下:

import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockTest { public static void main(String args[]) { LockObject lo = new LockObject(); MyThread t1 = new MyThread(lo); MyThread t2 = new MyThread(lo); Thread ta = new Thread(t1, "A"); Thread tb = new Thread(t2, "B"); ta.start(); tb.start(); } } class LockObject { Lock lock = new ReentrantLock(); public void LockFuc() { if (lock.tryLock()) { try { System.out.println(Thread.currentThread().getName() + "得到了锁"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); System.out.println(Thread.currentThread().getName() + "释放了锁"); } }else{ System.out.println(Thread.currentThread().getName() + "没有得到锁"); } } } class MyThread implements Runnable { LockObject lo = null; public MyThread(LockObject lo) { this.lo = lo; } @Override public void run() { // TODO Auto-generated method stub lo.LockFuc(); } }

tryLock()方法是有返回值的,它表示用来尝试获得锁,如果获得成功,则返回true,如果获得失败(即锁已被其他线程获得),则返回false,也就说这个方法不管如何都会立即返回。在拿不到锁时不会1直在那等待,履行结果以下:
A得到了锁
B没有得到锁
A释放了锁

3 tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区分在于这个方法在拿不到锁时会等待1定的时间,在时间期限以内如果还拿不到锁,就返回false。如果如果1开始拿到锁或在等待期间内拿到了锁,则返回true。

4 lockInterruptibly(),代码以下:

import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockTest { public static void main(String args[]) { LockObject lo = new LockObject(); MyThread t1 = new MyThread(lo); MyThread t2 = new MyThread(lo); Thread ta = new Thread(t1, "A"); Thread tb = new Thread(t2, "B"); ta.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } tb.start(); tb.interrupt(); } } class LockObject { Lock lock = new ReentrantLock(); public void LockFuc() throws InterruptedException { lock.lockInterruptibly(); try { System.out.println(Thread.currentThread().getName() + "得到了锁"); while(true){ ; } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); System.out.println(Thread.currentThread().getName() + "释放了锁"); } } } class MyThread implements Runnable { LockObject lo = null; public MyThread(LockObject lo) { this.lo = lo; } @Override public void run() { // TODO Auto-generated method stub try{ lo.LockFuc(); }catch(InterruptedException e){ System.out.println(Thread.currentThread().getName()+"被中断"); } } }

lock.lockInterruptibly()想获得某个锁时,假若此时线程A获得到了锁,而线程B只有在等待,那末对线程B调用threadB.interrupt()方法能够中断线程B的等待进程。履行结果以下:
A得到了锁
B被中断

下面来看读写锁ReadWriteLock,可以实现读和读不冲突:

import java.util.concurrent.locks.ReentrantReadWriteLock; public class LockTest { public static void main(String args[]) { LockObject lo = new LockObject(); MyThread t1 = new MyThread(lo); MyThread t2 = new MyThread(lo); Thread ta = new Thread(t1, "A"); Thread tb = new Thread(t2, "B"); ta.start(); tb.start(); } } class LockObject { ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void LockFuc(){ lock.readLock().lock(); try { System.out.println(Thread.currentThread().getName() + "得到了锁"); for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName() + "正在进行读操作" + i); } } catch (Exception e) { e.printStackTrace(); } finally { lock.readLock().unlock(); System.out.println(Thread.currentThread().getName() + "释放了锁"); } } } class MyThread implements Runnable { LockObject lo = null; public MyThread(LockObject lo) { this.lo = lo; } @Override public void run() { // TODO Auto-generated method stub lo.LockFuc(); } }

履行结果以下:
A得到了锁
B得到了锁
A正在进行读操作0
B正在进行读操作0
A正在进行读操作1
B正在进行读操作1
A正在进行读操作2
B正在进行读操作2
A正在进行读操作3
B正在进行读操作3
B正在进行读操作4
B正在进行读操作5
B正在进行读操作6
B正在进行读操作7
B正在进行读操作8
B正在进行读操作9
A正在进行读操作4
A正在进行读操作5
B释放了锁
A正在进行读操作6
A正在进行读操作7
A正在进行读操作8
A正在进行读操作9
A释放了锁
可以看到读和读其实不冲突,但是如果有Synchronized修饰的话,会发现是冲突的。

接下来讲下Condition:Condition是在java 1.5中才出现的,它用来替换传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition1的await()、signal()这类方式实现线程间协作更加安全和高效。因此通常来讲比较推荐使用Condition,Conditon中的await()对应Object的wait();Condition中的signal()对应Object的notify();Condition中的signalAll()对应Object的notifyAll(),接下来看个例子,重写生产者与消费者:

import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /* * 生产者与消费者问题 */ public class ProduceConsume { public static void main(String[] args) { SyncStack ss = new SyncStack(); Produce pd = new Produce(ss); Consume cs = new Consume(ss); Thread t1 = new Thread(pd); Thread t2 = new Thread(cs); t1.start(); t2.start(); } } /* * 馒头实体类 */ class ManTou { private int id; public ManTou(int id) { this.id = id; } public int getId() { return this.id; } @Override public String toString() { // TODO Auto-generated method stub return "ManTou " + getId(); } } /* * 馒头框类 */ class SyncStack { Lock lock = new ReentrantLock(); Condition full = lock.newCondition(); Condition empty = lock.newCondition(); int index = 0; ManTou[] mtArray = new ManTou[6]; public void push(ManTou mt) { lock.lock(); try { while (index == mtArray.length) { try { full.await(); } catch (InterruptedException e) { e.printStackTrace(); } } empty.signal(); mtArray[index] = mt; index++; System.out.println("生产了" + mt); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void pop() { lock.lock(); try { while (index == 0) { try { empty.await(); } catch (InterruptedException e) { e.printStackTrace(); } } full.signal(); index--; System.out.println("消费了" + mtArray[index]); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } } /* * 生产者 */ class Produce implements Runnable { SyncStack ss = null; public Produce(SyncStack ss) { this.ss = ss; } @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 20; i++) { ManTou mt = new ManTou(i); if (ss != null) { ss.push(mt); } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } } /* * 消费者 */ class Consume implements Runnable { SyncStack ss = null; public Consume(SyncStack ss) { this.ss = ss; } @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 20; i++) { if (ss != null) { ss.pop(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }

跟之前Object的wait()、notify()的写法很类似。
以上如有问题,欢迎指正,谢谢。

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐