并发5-synchronized和Lock

1.上一篇说到了synchronized的缺陷:

    synchronized的缺陷:

    1.使用synchronized包住的代码块,只可能有两种状态:顺利执行完毕释放锁,执行发生异常释放锁,不会由于异常导致出现死锁现象

    2.如果synchronized包住的代码块中有sleep等操作,比如I/O阻塞,但是其他线程还是需要等待,这样程序的效率就比较低了

    3.等待synchronized释放锁的线程会一直等待下去(死心塌地,不到黄河心不死)



由此可见,synchronized并不是最好的锁,是由缺点的。

有如下场景:

    对a.txt这个文件,A,B线程都可以进行读写,写操作与写操作会发生冲突,写操作与读操作会发生冲突,但是,读操作与读操作不会发生冲突

    就需要有某种锁,可以在读操作与读操作之间,不会发生冲突  

    这里介绍另外一种可以控制临界资源访问的锁



2.Lock:

    Lock接口解决了synchronized的缺陷。

 
 
  1. public interface Lock {

  2.    void lock();

  3.    void lockInterruptibly() throws InterruptedException;

  4.    boolean tryLock();

  5.    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

  6.    void unlock();

  7.    Condition newCondition();

  8. }

    通过Lock的源码可以知道,lock(),tryLock(),tryLock(long time,Time Unit),lockInterruptiably()是用来获取锁的

    lock()方法是平常使用得最多的一个方法,用来获取锁,如果锁已经被其他线程获取,则进行等待,可以说和synchronized没有差别

 
 
  1. Lock lock = ...;

  2. lock.lock();

  3. try{

  4.    //处理任务

  5. }catch(Exception ex){

  6.    

  7. }finally{

  8.    lock.unlock();   //释放锁

  9. }

   

 
 
  1. /**

  2. * Created by liuyl on 15/11/27.

  3. */

  4. public class ThreadLock {

  5.    private ReentrantLock lock = new ReentrantLock();

  6.    public static void main(String[] args) {

  7.        ThreadLock mt = new ThreadLock();

  8.        new Thread(){

  9.            @Override

  10.            public void run() {

  11.                mt.insert(this);

  12.            }

  13.        }.start();

  14.        new Thread(){

  15.            @Override

  16.            public void run() {

  17.                mt.insert(this);

  18.            }

  19.        }.start();

  20.    }

  21.    public void insert(Thread thread){

  22.        //获得锁

  23.        lock.lock();

  24.        try {

  25.            System.out.println(Thread.currentThread().getName()+"获得锁");

  26.        } catch (Exception e) {

  27.        //一定要在这边释放锁

  28.        }finally {

  29.            System.out.println(Thread.currentThread().getName()+"释放锁");

  30.            lock.unlock();

  31.        }

  32.    }

  33. }

    

    tryLock()是有返回值的,且会立即返回,不会一直等待,如果获取到锁,则返回true,否则返回false

 
 
  1. Lock lock = ...;

  2. if(lock.tryLock()) {

  3.     try{

  4.         //处理任务

  5.     }catch(Exception ex){

  6.        

  7.     }finally{

  8.         lock.unlock();   //释放锁

  9.     }

  10. }else {

  11.    //如果不能获取锁,则直接做其他事情

  12. }

      tryLock()的示例代码:

 
 
  1. public class ThreadLock2 {

  2.    private ReentrantLock lock = new ReentrantLock();

  3.    public static void main(String[] args) {

  4.        ThreadLock2 mt = new ThreadLock2();

  5.        new Thread() {

  6.            @Override

  7.            public void run() {

  8.                mt.insert(this);

  9.            }

  10.        }.start();

  11.        new Thread() {

  12.            @Override

  13.            public void run() {

  14.                mt.insert(this);

  15.            }

  16.        }.start();

  17.    }

  18.    public void insert(Thread thread) {

  19.        if (lock.tryLock()) {

  20.            try {

  21.                System.out.println(thread.getName() + "得到了锁");

  22.            } catch (Exception e) {

  23.            } finally {

  24.                try {

  25.                    Thread.sleep(1000);

  26.                } catch (InterruptedException e) {

  27.                    e.printStackTrace();

  28.                }

  29.                System.out.println(thread.getName() + "释放了锁");

  30.                lock.unlock();

  31.            }

  32.        } else {

  33.            System.out.println(thread.getName() + "获取锁失败");

  34.        }

  35.    }
  36. }


        lockInterruptibly()当这个方法正在获取锁时,能够响应中断。

 
 
  1. public void method() throws InterruptedException {

  2.    lock.lockInterruptibly();

  3.    try {  

  4.     //.....

  5.    }

  6.    finally {

  7.        lock.unlock();

  8.    }  

  9. }


    示例代码:

  
  
  1. public class ThreadLock3 {
  2.    private Lock lock = new ReentrantLock();
  3.    public static void main(String[] args) {
  4.        ThreadLock3 test = new ThreadLock3();
  5.        MyThread thread1 = new MyThread(test);
  6.        MyThread thread2 = new MyThread(test);
  7.        thread1.start();
  8.        thread2.start();
  9.        try {
  10.            Thread.sleep(2000);
  11.        } catch (InterruptedException e) {
  12.            e.printStackTrace();
  13.        }
  14.        thread2.interrupt();
  15.    }
  16.    public void insert(Thread thread) throws InterruptedException {
  17.        lock.lockInterruptibly();   //注意,如果需要正确中断等待锁的线程,必须将获取锁放在外面,然后将InterruptedException抛出
  18.        try {
  19.            System.out.println(thread.getName() + "得到了锁");
  20.            long startTime = System.currentTimeMillis();
  21.            for (; ; ) {
  22.                if (System.currentTimeMillis() - startTime >= Integer.MAX_VALUE)
  23.                    break;
  24.            //   thrad1在这边一直卡住
  25.            }
  26.        } finally {
  27.            System.out.println(Thread.currentThread().getName() + "执行finally");
  28.            lock.unlock();
  29.            System.out.println(thread.getName() + "释放了锁");
  30.        }
  31.    }
  32. }
  33. class MyThread extends Thread {
  34.    private ThreadLock3 test = null;
  35.    public MyThread(ThreadLock3 test) {
  36.        this.test = test;
  37.    }
  38.    @Override
  39.    public void run() {
  40.        try {
  41.            test.insert(Thread.currentThread());
  42.        } catch (InterruptedException e) {
  43.            System.out.println(Thread.currentThread().getName() + "被中断");
  44.        }
  45.    }
  46. }

    ReentranReadWriteLock分为readLock()和writeLock()来获取读写锁

  
  
  1. public class ReadAndWriteLOck {
  2.    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
  3.    private ArrayList<Integer> list = new ArrayList<>();
  4.    public static void main(String[] args) {
  5.        ReadAndWriteLOck mt = new ReadAndWriteLOck();
  6.        new Thread(){
  7.            @Override
  8.            public void run() {
  9.                mt.insert(Thread.currentThread());
  10.            }
  11.        }.start();
  12.        new Thread(){
  13.            @Override
  14.            public void run() {
  15.                mt.insert(Thread.currentThread());
  16.            }
  17.        }.start();
  18.    }
  19.    public void insert(Thread thread){
  20.        lock.readLock().lock();
  21.        try {
  22.            long start = System.currentTimeMillis();
  23.            while(System.currentTimeMillis() - start <= 200) {
  24.                System.out.println(thread.getName()+"正在进行读操作");
  25.            }
  26.            System.out.println(thread.getName()+"读操作完毕");
  27.        } finally {
  28.            lock.readLock().unlock();
  29.        }
  30.    }
  31. }

    输出结果:

        线程0和线程1交替执行


Lock和synchronized的选择:

    1.Lock是java内置的一个类,synchronized是关键字

    2.Lock必须要使用unlock()方法在finally中释放如果没有主动释放锁,就有可能导致出现死锁现象,发生异常时不会自动释放,synchronized发生异常时会自动释放

    3.Lock在等待获取锁的时候可以响应中断,synchronize则不会

    4.Lock可以知道获取锁是否成功

    5.Lock有读写锁功能

    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值