第四章-java多线程核心技术-Lock锁-第一篇

lock锁的使用

ReentrantLock锁的使用

在JDK5.0版本以前,重入锁的性能远远好于synchronized关键字,JDK6.0版本以后synchronized 获得了大量的优化,两者性能也不分伯仲,可是重入锁是能够彻底替代synchronized关键字的。除此以外,重入锁又自带一系列其余功能:可中断响应、锁申请等待限时、公平锁。另外能够结合Condition来使用,使其更是逼格满满。java

请看以下使用代码小程序

public class ReenTrantLock {
    private Lock lock = new ReentrantLock();

    public void testLock() {
        lock.lock();
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "---" + i);
        }
        lock.unlock();
    }

} 

/**
 * @program: demo
 * @description: demo
 * @author: lee
 * @create: 2018-09-03
 **/
public class ThreadA extends Thread {
    private  ReenTrantLock reenTrantLock ;

    public ThreadA(ReenTrantLock reenTrantLock) {
        this.reenTrantLock = reenTrantLock;
    }

    @Override
    public void run() {
        super.run();
        this.reenTrantLock.testLock();
    }
}

public class Run {
    public static void main(String[] args) {
        ReenTrantLock reenTrantLock = new ReenTrantLock();
        ThreadA threadA = new ThreadA(reenTrantLock);
        threadA.start();
        ThreadA threadB = new ThreadA(reenTrantLock);
        threadB.start();
        ThreadA threadC = new ThreadA(reenTrantLock);
        threadC.start();
        ThreadA threadD = new ThreadA(reenTrantLock);
        threadD.start();
    }
}

输出结果ide

Thread-0---0
Thread-0---1
Thread-0---2
Thread-0---3
Thread-0---4
Thread-0---5
Thread-0---6
Thread-0---7
Thread-0---8
Thread-0---9
Thread-1---0
Thread-1---1
Thread-1---2
Thread-1---3
Thread-1---4
Thread-1---5
Thread-1---6
Thread-1---7
Thread-1---8
Thread-1---9
...

ReentrantLock同步实现

请看以下代码性能

/**
 * @program: demo
 * @description: demo
 * @author: lee
 * @create: 2018-09-03
 **/
public class ReenTrantLock {
    private Lock lock = new ReentrantLock();

    public void testLock() {
        lock.lock();
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "---" + i);
        }
        lock.unlock();
    }

    public void testLockB() {
        lock.lock();
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "---" + i);
        }
        lock.unlock();
    }

}  

/**
 * @program: demo
 * @description: demo
 * @author: lee
 * @create: 2018-09-03
 **/
public class ThreadA extends Thread {
    private  ReenTrantLock reenTrantLock ;

    public ThreadA(ReenTrantLock reenTrantLock) {
        this.reenTrantLock = reenTrantLock;
    }

    @Override
    public void run() {
        super.run();
        this.reenTrantLock.testLock();
    }
}

public class ThreadB extends Thread {
    private  ReenTrantLock reenTrantLock ;

    public ThreadB(ReenTrantLock reenTrantLock) {
        this.reenTrantLock = reenTrantLock;
    }

    @Override
    public void run() {
        super.run();
        this.reenTrantLock.testLockB();
    }
}

public class Run {
    public static void main(String[] args) {
        ReenTrantLock reenTrantLock = new ReenTrantLock();
        ThreadA threadA = new ThreadA(reenTrantLock);
        threadA.start();
        ThreadB threadB = new ThreadB(reenTrantLock);
        threadB.start();
    }
}

输出结果学习

Thread-0---0
Thread-0---1
Thread-0---2
Thread-0---3
Thread-0---4
Thread-0---5
Thread-0---6
Thread-0---7
Thread-0---8
Thread-0---9
Thread-1---0
Thread-1---1
Thread-1---2
Thread-1---3
Thread-1---4
Thread-1---5
Thread-1---6
Thread-1---7
Thread-1---8
Thread-1---9

由输出结果可知,线程之间呈现互斥访问,即lock锁持有的是对象监视器,同一个锁修饰的线程之间的代码是互斥的。优化

lock锁实现等待通知

在前面咱们学习与synchronized锁配合的线程等待(Object.wait)与线程通知(Object.notify),那么对于JDK1.5 的 java.util.concurrent.locks.ReentrantLock 锁,JDK也为咱们提供了与此功能相应的类java.util.concurrent.locks.Condition。Condition与重入锁是经过lock.newCondition()方法产生一个与当前重入锁绑定的Condtion实例,咱们通知该实例来控制线程的等待与通知。该接口的全部方法:this

public interface Condition {
     //使当前线程加入 await() 等待队列中,并释放当锁,当其余线程调用signal()会从新请求锁。与Object.wait()相似。
    void await() throws InterruptedException;

    //调用该方法的前提是,当前线程已经成功得到与该条件对象绑定的重入锁,不然调用该方法时会抛出IllegalMonitorStateException。
    //调用该方法后,结束等待的惟一方法是其它线程调用该条件对象的signal()或signalALL()方法。等待过程当中若是当前线程被中断,该方法仍然会继续等待,同时保留该线程的中断状态。 
    void awaitUninterruptibly();

    // 调用该方法的前提是,当前线程已经成功得到与该条件对象绑定的重入锁,不然调用该方法时会抛出IllegalMonitorStateException。
    //nanosTimeout指定该方法等待信号的的最大时间(单位为纳秒)。若指定时间内收到signal()或signalALL()则返回nanosTimeout减去已经等待的时间;
    //若指定时间内有其它线程中断该线程,则抛出InterruptedException并清除当前线程的打断状态;若指定时间内未收到通知,则返回0或负数。 
    long awaitNanos(long nanosTimeout) throws InterruptedException;

    //与await()基本一致,惟一不一样点在于,指定时间以内没有收到signal()或signalALL()信号或者线程中断时该方法会返回false;其它状况返回true。
    boolean await(long time, TimeUnit unit) throws InterruptedException;

   //适用条件与行为与awaitNanos(long nanosTimeout)彻底同样,惟一不一样点在于它不是等待指定时间,而是等待由参数指定的某一时刻。
    boolean awaitUntil(Date deadline) throws InterruptedException;
    
    //唤醒一个在 await()等待队列中的线程。与Object.notify()类似
    void signal();

   //唤醒 await()等待队列中全部的线程。与object.notifyAll()类似
    void signalAll();
}

请看实际小程序线程

public class MyService {
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void testLock() {
        try {
            lock.lock();
            System.out.println("即将进入wait唤醒");
            condition.await();
            System.out.println("wait唤醒");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void testLockB() {
        try {
            lock.lock();
            System.out.println("即将唤醒线程");
            condition.signal();
        }finally {
            lock.unlock();
        }

    }

}    

public class ThreadA extends Thread {
    private MyService reenTrantLock ;

    public ThreadA(MyService reenTrantLock) {
        this.reenTrantLock = reenTrantLock;
    }

    @Override
    public void run() {
        super.run();
        this.reenTrantLock.testLock();
    }
}

public class ThreadB extends Thread {
    private MyService reenTrantLock ;

    public ThreadB(MyService reenTrantLock) {
        this.reenTrantLock = reenTrantLock;
    }

    @Override
    public void run() {
        super.run();
        this.reenTrantLock.testLockB();
    }
}

public class Run {
    public static void main(String[] args) {

        try {
            MyService service = new MyService();
            ThreadA threadA = new ThreadA(service);
            threadA.start();
            Thread.sleep(1000);
            ThreadB threadB = new ThreadB(service);
            threadB.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

输出结果code

即将进入wait唤醒
即将唤醒线程
wait唤醒

通知部分线程

请看以下代码对象

public class MyService {
    private Lock lock = new ReentrantLock();

    private Condition condition = lock.newCondition();

    private Condition condition2 = lock.newCondition();

    public void testLock() {
        try {
            lock.lock();
            System.out.println("condition即将进入wait唤醒");
            condition.await();
            System.out.println("condition wait已经唤醒唤醒");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void testLockB() {
        try {
            lock.lock();
            System.out.println("condition2即将进入wait唤醒");
            condition2.await();
            System.out.println("condition2 wait已经唤醒唤醒");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public void callCondition() {
        try {
            lock.lock();
            condition.signal();
            System.out.println("即将唤醒Condition");
        }finally {
            lock.unlock();
        }
    }

    public void callCondition2() {
        try {
            lock.lock();
            condition2.signal();
            System.out.println("即将唤醒Condition2");
        }finally {
            condition2.signal();
        }
    }

}   

public class ThreadA extends Thread {
    private MyService reenTrantLock ;

    public ThreadA(MyService reenTrantLock) {
        this.reenTrantLock = reenTrantLock;
    }

    @Override
    public void run() {
        super.run();
        this.reenTrantLock.testLock();
    }
}

public class ThreadB extends Thread {
    private MyService reenTrantLock ;

    public ThreadB(MyService reenTrantLock) {
        this.reenTrantLock = reenTrantLock;
    }

    @Override
    public void run() {
        super.run();
        this.reenTrantLock.testLockB();
    }
}

public class Run {
    public static void main(String[] args) {

        try {
            MyService service = new MyService();
            ThreadA threadA = new ThreadA(service);
            threadA.start();
            ThreadB threadB = new ThreadB(service);
            threadB.start();
            Thread.sleep(1000);
            service.callCondition();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

输出结果

condition即将进入wait唤醒
condition2即将进入wait唤醒
即将唤醒Condition
condition wait已经唤醒唤醒

此时程序仍未结束,还在处于运行状态,由于其中一个线程还在处于等待状态。

lock实现单生产者单消费着模式

请看以下代码

public class Product {
    public static boolean hasValue =false;
}    

public class MyService {
    private Lock lock = new ReentrantLock();
    private boolean hasValue = false;
    private Condition condition = lock.newCondition();

    public void product() {
        try {
            lock.lock();
            while (true) {
                if (Product.hasValue) {
                    condition.await();
                }
                System.out.println("生产了一个物品");
                Product.hasValue = true;
                condition.signal();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void consume() {
        try {
            lock.lock();
            while (true) {
                if (!Product.hasValue) {
                    condition.await();
                }
                System.out.println("消费了一个物品");
                Product.hasValue = false;
                condition.signal();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}  

public class ThreadA extends Thread {
    private MyService reenTrantLock ;

    public ThreadA(MyService reenTrantLock) {
        this.reenTrantLock = reenTrantLock;
    }

    @Override
    public void run() {
        super.run();
        this.reenTrantLock.product();
    }
}

public class ThreadB extends Thread {
    private MyService reenTrantLock ;

    public ThreadB(MyService reenTrantLock) {
        this.reenTrantLock = reenTrantLock;
    }

    @Override
    public void run() {
        super.run();
        this.reenTrantLock.consume();
    }
}

输出结果

生产了一个物品
消费了一个物品
生产了一个物品
消费了一个物品
生产了一个物品
消费了一个物品
生产了一个物品
消费了一个物品
生产了一个物品
消费了一个物品
....

公平锁和非公平锁

公平锁和非公平锁

公平锁的意思就是线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出的方式,并不必定所有是。非公平锁就是指线程随机获取到锁,先加锁的不必定先得到锁,这种方式可能形成一些线程老是拿不到锁,结果也就是不公平的。

请看以下代码

//final MyService service = new MyService(true); 非公平锁
public class MyService {
    private ReentrantLock lock ;
    private boolean isFair;

    public MyService(boolean isFair) {
        this.isFair = isFair;
        lock =  new ReentrantLock(this.isFair);
    }
    public void serviceMethod() {
        try {
            lock.lock();
            System.out.println("得到锁的线程名称是" + Thread.currentThread().getName());
        } finally {
            lock.unlock();
        }
    }
}


public class Run {
    public static void main(String[] args) {

        final MyService service = new MyService(true);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("当前线程是" + Thread.currentThread().getName());
                service.serviceMethod();
            }
        };

        Thread[] threads = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(runnable);

        }

        for (int i=0;i<10;i++){
            threads[i].start();
        }

    }
}

输出结果

当前线程是Thread-0
得到锁的线程名称是Thread-0
当前线程是Thread-1
得到锁的线程名称是Thread-1
当前线程是Thread-2
得到锁的线程名称是Thread-2
当前线程是Thread-3
得到锁的线程名称是Thread-3
当前线程是Thread-4
得到锁的线程名称是Thread-4
当前线程是Thread-5
得到锁的线程名称是Thread-5
当前线程是Thread-6
得到锁的线程名称是Thread-6
当前线程是Thread-7
当前线程是Thread-8
得到锁的线程名称是Thread-7
得到锁的线程名称是Thread-8
当前线程是Thread-9
得到锁的线程名称是Thread-9

得到的线程基本呈现有序状态

相关文章
相关标签/搜索