美文网首页
《Java多线程编程核心技术_高洪岩 著》读后整理04

《Java多线程编程核心技术_高洪岩 著》读后整理04

作者: Jthan | 来源:发表于2017-05-18 17:41 被阅读0次

    第4章 Lock的使用

    在Java多线程中, 可以使用synchronized关键字来实现线程之间同步互斥,但在JDK1.5中新增加了ReentrantLock类也能达到同样的效果,并且在扩展功能上也更加强大。

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     */
    public class MyService {
    
        private Lock lock = new ReentrantLock();
    
        public void testMethod() {
            lock.lock();
            for (int i = 0; i < 5; i++) 
                System.out.println("ThreadName=" + Thread.currentThread().getName() + (" " + (i + 1)));
            lock.unlock();
        }
    }
    
    class MyThread extends Thread {
        private MyService service;
    
        public MyThread(MyService service) {
            this.service = service;
        }
    
        @Override
        public void run() {
            service.testMethod();
        }
    }
    
    class Run {
        public static void main(String[] args) {
            MyService service = new MyService();
            
            MyThread t1 = new MyThread(service);
            MyThread t2 = new MyThread(service);
            MyThread t3 = new MyThread(service);
            MyThread t4 = new MyThread(service);
            MyThread t5 = new MyThread(service);
            t1.start();
            t2.start();
            t3.start();
            t4.start();
            t5.start();
        }
    }
    
    OUTPUT:
    ThreadName=Thread-0 1
    ThreadName=Thread-0 2
    ThreadName=Thread-0 3
    ThreadName=Thread-0 4
    ThreadName=Thread-0 5
    ThreadName=Thread-2 1
    ThreadName=Thread-2 2
    ThreadName=Thread-2 3
    ThreadName=Thread-2 4
    ThreadName=Thread-2 5
    ThreadName=Thread-3 1
    ThreadName=Thread-3 2
    ThreadName=Thread-3 3
    ThreadName=Thread-3 4
    ThreadName=Thread-3 5
    ThreadName=Thread-4 1
    ThreadName=Thread-4 2
    ThreadName=Thread-4 3
    ThreadName=Thread-4 4
    ThreadName=Thread-4 5
    ThreadName=Thread-1 1
    ThreadName=Thread-1 2
    ThreadName=Thread-1 3
    ThreadName=Thread-1 4
    ThreadName=Thread-1 5
    
    • 调用lock.lock()代码的线程就持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢。效果和使用synchronized关键字一样,线程之间执行的顺序是随机的。

    • Condition对象的await()方法,使当前执行任务的线程进入了等待WAITING状态。

    • Condition实现等待 / 通知

    import java.util.concurrent.*;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    //在调用condition.await()方法之前需调用lock.lock()代码获得同步监视器
    public class MyService3 {
        private Lock lock = new ReentrantLock();
        private Condition condition = lock.newCondition();
    
        public void await() {
            try {
                lock.lock();
                System.out.println("A");
                condition.await();//等待
                System.out.println("B");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    
        public void single() {
            try {
                lock.lock();
                condition.signal();//唤醒
            } finally {
                lock.unlock();
            }
        }
    }
    
    class Run3 {
        public static void main(String[] args) throws InterruptedException {
            final MyService3 service = new MyService3();
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    service.await();
                }
            });
            thread.start();
    
            System.out.println(Thread.currentThread().getName());
            Thread.sleep(1);
    
            service.single();
        }
    }
    
    • 在使用notify()/notifyAll()方法进行通知时,被通知的线程却是由JVM随机选择的。但使用ReentrantLock结合Condition类是可以实现"选择性通知“。

    Object类中的wait()方法相当于Condition类中的await()方法

    Object类中的wait(long timeout)方法相当于Condition类中的`await(long time, TimeUnit unit)方法

    Object类中的notify()方法相当于Condition类中的signal()方法。

    Object类中的notifyAll()方法相当于Condition类中的signalAll()方法。

    • 公平与非wcguqim:锁Lock分为“公平锁”和“非公平锁”, 公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。而非公平锁就是一种获取锁的抢占机制,是随机获得锁的,和公平锁不一样的就是先来不一定先得到锁,这个方式可能造成某些线程一直拿不锁,结果也就是不公平的了。

    getHoldCount(), getQueueLength(), getWaitQueueLength()
    • 方法int getHoldCount()的作用是查询当前线程保持此锁定的个数,也就是调用lock()方法的次数。
    lock.getHoldCount();
    
    • 方法int getQueueLength()的作用是返回正等待获取此锁定的线程估计数,比如有5个线程,1个线程首先执行await()方法,那么在调用getQueueLength()方法反返回值是4,说明有4个线程同时在等待lock的释放。
    lock.getQueueLength();
    
    • 方法int getWaitQueueLength(Condition condition)的作用是返回等待与此锁定相关的给定条件Condition的线程估计数,比如有5个线程,每个线程都执行了同一个condition对象的await()方法,则调用getWaitQueueLength(Condition condition)方法时返回的int值是5。

    hasQueuedThread(), hasQueuedThreads(), hasWaiters()
    • 方法boolean hasQueuedThread(thtread thread)的作用是查询指定的线程是否正在等待获取此锁定。

    • 方法boolean hasQueuedThreads()的作用是查询是否有线程正在等待获取此锁定。

    lock.hasQueuedThread(threadA);
    lock.hasQueuedThreads();
    
    • 方法boolean hasWaiters(Condition condition)的作用是查询是否有线程正在等待与此锁定有关的condition条件。
    lock.hasWaiters(newConditino);
    

    isFair(), isHeldByCurrentThread(), isLocked()
    • 方法boolean isFair()的作用是判断是不是公平锁。在默认的情况下,ReentrantLock类使用的是非公平锁。
    lock.isFair();
    
    • 方法boolean isHeldByCurrentThread()的作用是查询当前线程是否保持此锁定。
    lock.isHeldByCurrentThread();
    
    • 方法boolean isLocked()的作用是查询此锁定是否由任意线程保持。
    lock.isLocked();
    

    lockInterruptibly(), tryLock(), tryLock(long timeout,TimeUnit unit)
    • 方法void lockInterruptibly()的作用是:如果当前线程未衩中断,则获取锁定,如果已经被中断则出现异常。

    • 方法boolean tryLock()的作用是,仅在调用时锁定未被另一个线程保持的情况下,才获取该锁定。

    • 方法boolean tryLock(long timeout, TimeUnit unit)的作用是,如果锁定在给定等待时间内没有被别一个线程保持,且当前线程未被中断,则获取该锁定。


    ReentrantReadWriteLock
    • 类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务。这样做虽然保证了实例变量的线程安全性,但效率却是非常低下的。

    • 所以在JDK中提供了一种读写锁ReentrantReadWriteLock类,使用它可以加快运行效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁ReentratnReadWriteLock来提升该方法的代码运行速度。

    • 永定锁表示也有两个锁,一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的锁,也叫排他锁。也就是多个读锁之间不互斥,写写、写读互斥。

    ...
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    ...
    lock.writeLock().lock();
    lock.readLock().lock();
    ...
    lock.wirteLock().unlock();
    lock.readLock().unlock();
    

    相关文章

      网友评论

          本文标题:《Java多线程编程核心技术_高洪岩 著》读后整理04

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