美文网首页
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