美文网首页
2、并发编程(二)

2、并发编程(二)

作者: ltjxwxz | 来源:发表于2017-12-17 22:49 被阅读0次

    一、ReentrantLock

    1.1、reentrantlock用于替代synchronized
      synchronized手动上锁,自动释放
      reentrantlock手动上锁,手动释放
      注意: ReentrantLock是手动锁,执行结束必须要必须要必须要手动释放锁。遇到异常,jvm会自动释放锁,但是lock必须手动释放锁,因此经常在finally中进行锁的释放

    public class MyReentrantLock1 {
    
        Lock lock = new ReentrantLock();
    
        public void m1() {
            System.out.println("m1开始执行");
            try {
                lock.lock();
                for(int i=0; i<10; i++) {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println("i:" + i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public void m2() {
            lock.lock();
            System.out.println("m2开始执行");
            lock.unlock();
        }
    
        public static void main(String[] args) {
            MyReentrantLock1 r1 = new MyReentrantLock1();
            new Thread(r1::m1).start();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(r1::m2).start();
        }
    }
    

    1.2、“尝试锁定”ReentrantLock的tryLock方法,这样无法锁定,或者在指定时间内无法锁定,线程可以决定是否继续等待。
      也可以指定tryLock的时间,由于tryLock(time)抛出异常,所以要注意unclock的处理,必须放到finally中

    public class ReentrantLock3 {
        Lock lock = new ReentrantLock();
    
        void m1() {
            try {
                lock.lock();
                for (int i = 0; i < 10; i++) {
                    TimeUnit.SECONDS.sleep(1);
    
                    System.out.println(i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        /**
         * 使用tryLock进行尝试锁定,不管锁定与否,方法都将继续执行
         * 可以根据tryLock的返回值来判定是否锁定
         * 也可以指定tryLock的时间,由于tryLock(time)抛出异常,所以要注意unclock的处理,必须放到finally中
         */
        void m2() {
            /*
            boolean locked = lock.tryLock();
            System.out.println("m2 ..." + locked);
            if(locked) lock.unlock();
            */
            boolean locked = false;
            
            try {
                locked = lock.tryLock(5, TimeUnit.SECONDS);
                System.out.println("m2 ..." + locked);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                if(locked) lock.unlock();
            }
        }
    
        public static void main(String[] args) {
            ReentrantLock3 rl = new ReentrantLock3();
            new Thread(rl::m1).start();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(rl::m2).start();
        }
    }
    

    1.3、ReentrantLock的lockInterruptibly方法,可以对线程interrupt方法做出响应,在一个线程等待锁的过程中,可以被打断。
    下面的程序,由于thread1一直执行,thread2始终无法获取锁,就一直等待,所以尝试打断thread2,如果thread2中用lock.lock()锁定,此时无法打断thread2,如果用lock.lockInterruptibly()既可以打断thread2

    public class MyReentrantLock4 {
    
        public static void main(String[] args) {
            Lock lock = new ReentrantLock();
    
            Thread thread1 = new Thread(()->{
                try {
                    System.out.println("t1 start....");
                    lock.lock();
                    TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
                    System.out.println("t1 end....");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            thread1.start();
    
            Thread thread2 = new Thread(()->{
                boolean locked = false;
                try {
    //                lock.lock();
                    lock.lockInterruptibly();
                    locked = lock.tryLock();
                    System.out.println("t2 start....");
                    TimeUnit.SECONDS.sleep(5);
                    System.out.println("t2 end....");
                } catch (InterruptedException e) {
                    System.out.println("interrupted!");
                } finally {
                    if(locked) {
                        lock.unlock();
                    }
                }
            });
            thread2.start();
    
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            thread2.interrupt();
        }
    }
    

    1.4、reentrantlock可以指定为公平锁

    2、生产者消费者
      写一个固定容量同步容器,拥有put和get方法,以及getCount方法,能够支持2个生产者线程以及10个消费者线程的阻塞调用
    2.1、 wait,notify实现
    (1)wait 99%的情况跟while一起用,而不是和if一起用。原因:在执行之前会进入while再检查一遍,while会一直判断,if只会判断一次,如果有多个线程等待,会不安全。
    (2)用notifyAll而不是notify。原因:如果用notify可能出现一个生产者叫醒另外一个也是生产者,被叫醒的生产者也wait了,程序无法继续执行。

    2.2、ReentrantLock Condition实现,精确指定哪个线程被唤醒

    相关文章

      网友评论

          本文标题:2、并发编程(二)

          本文链接:https://www.haomeiwen.com/subject/zjulwxtx.html