java基础之线程 Lock接口

把java基础撸一边,从简单的开始。html

线程部分:java

特别说明来源:

抄了的网站:java并发编程-Lock
编程

Lock的须要

在java中,已经有了synchronize来当锁,为何还要Lock呢?bash

被synchronize修饰的方法,当一个线程得到了对应的锁以后,并执行该代码块时,其余线程只能一直等待,其余线程获取锁的状况会有三种。并发

1:执行完该代码块,而后线程释放对锁的占有jvm

2:线程执行发生异常,此时jvm会让线程自动释放锁ide

3:这个主要是在等待唤醒机制里面的wait()方法工具

那么若是这个获取锁的线程要等待IO或其余被阻塞了,但没有释放,其余线程只能干巴巴地等。这样会影响效率,所以咱们须要不论程序的代码块执行的如何最终都将锁对象进行释放,方便其余线程的执行性能

这个时候就须要用到lock优化

1:Lock不是java的语音内置的,synchronize是java的关键字,所以是内置特性。Lock是一个类,经过这个类能够实现同步方法

2:synchronize是在JVM层面上实现的,不但能够经过一些监控工具监控synchronize的锁定,并且在代码执行出现异常,jvm会自动释放锁定,但lock则不行,lock是经过代码执行的,要保证锁必定会被释放,就必须将nuLock放到finally中

3:在资源竞争不是很激烈的状况下,synchronize的性能要优于ReetranLock,但在资源竞争很激烈的状况下,Synchronize的性能会降低几十倍

Lock的使用

Lock是一个抽象类,接口Lock的类有,ReentrantLock 可重入锁,ReadWriteLock读写锁,

ReentantReadWriteLock可重入读写锁,StampedLock

Lock的方法:

//获取锁
void lock();
//获取锁的过程能响应中断
void lockInterruptibly() throws InterruptedException;
//获取锁返回true,不然返回false
boolean tryLock();
//超时获取锁,在规定时间未获取到锁返回false
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
释放锁
void unlock();
//获取与lock绑定的等待通知组件,在前现场必须先得到了锁才能等待,等待会释放锁,
//再次获取到锁才能从等待中返回
Condition newCondition();

复制代码

ReentrantLock使用

在实现类中,用的比较多的是ReentrantLock。下面对这个类的使用作个介绍

public class Demo51  {

    Lock lock = new ReentrantLock(); //建立这个类的失恋,保证惟一
    public void insert(Thread thread) {
        if (lock.tryLock()){ //获取锁
            try {
                System.out.println(thread.getName()+"获得了锁");
            } catch (Exception e) {
                // TODO: handle exception
            }finally {
                System.out.println(thread.getName()+"释放了锁");
                lock.unlock(); //记得释放锁
            }
        }else {
            System.out.println(thread.getName()+"获取锁失败");
        }
    }

    public static void main(String[] age){
        final Demo51 test = new Demo51();

        new Thread(){
            public void run() {
                test.insert(Thread.currentThread());
            };
        }.start();

        new Thread(){
            public void run() {
                test.insert(Thread.currentThread());
            };
        }.start();
    }

}复制代码

打印

Thread-0获得了锁
Thread-0释放了锁
Thread-1获得了锁
Thread-1释放了锁
复制代码

这里使用了两个方法

tryLock和unlock 一个获取,一个释放,有获取就必定要有释放。这个和synchronize不同,当执行完方法的时候会自动释放,让下个线程获取锁,但这个必须代码

public class Demo52 {

    private Lock lock = new ReentrantLock();
    public static void main(String[] args)  {
        Demo52 test = new Demo52();
        MyThread thread1 = new MyThread(test);
        MyThread thread2 = new MyThread(test);
        thread1.start();
        thread2.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread2.interrupt();
    }

    public void insert(Thread thread) throws InterruptedException{
        lock.lockInterruptibly();   //注意,若是须要正确中断等待锁的线程,必须将获取锁放在外面,而后将InterruptedException抛出
        try {
            System.out.println(thread.getName()+"获得了锁");
            long startTime = System.currentTimeMillis();
            for(int i = 0 ;i < 20 ; i ++     ) {
                Thread.sleep(200);
                if(System.currentTimeMillis() - startTime >= Integer.MAX_VALUE)
                    break;
                //插入数据
            }
        }
        finally {
            System.out.println(Thread.currentThread().getName()+"执行finally");
            lock.unlock();
            System.out.println(thread.getName()+"释放了锁");
        }
    }

    static class MyThread extends Thread{
        private Demo52 demo52 = null;
        public MyThread(Demo52 demo52){
            this.demo52 = demo52;
        }
        @Override
        public void run() {
            try {
                demo52.insert(Thread.currentThread());
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName()+"被中断");
            }
        }
    }
}复制代码

打印

Thread-0获得了锁
Thread-1被中断
Thread-0执行finally
Thread-0释放了锁
复制代码

在Thread-0拿到锁以后,Thread-1判断,若是锁被占用,会中断

(还有几个java原生实现了Lock的接口。后续再补吧!给本身留的做业)

手写实现Lock接口类

目标:

1:实现获取锁lock()和释放unlock()方法

2:实现重入锁

初步实现

实现Lock抽象类

public class MyLock5 implements Lock {

    private boolean isLock = false ;

    @Override
    public synchronized void lock() {
        while (isLock){
            try {
                wait(); //等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isLock = true ;
    }

    @Override
    public synchronized void unlock() {
                notify(); //唤醒
                isLock = false ;
    }
}复制代码

在lock()方法里面对进入的线程进行判断,若是已经有线程进入会是isLock会是true,进入wait等待状态中。执行unlock方法后isLock 为true 这样就能够不须要等待去执行方法

public class Demo54 {

    private Lock lock = new MyLock5();

    int value = 0 ;

    public int getNext(){
        lock.lock();
        value++ ;
        lock.unlock();
        return value ;

    }

    public static void main(String[] age){
        Demo54 demo54 = new Demo54();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (;;)
                System.out.println(""+demo54.getNext());
            }
        }).start();
    }

}复制代码

打印:

235842
235843
235844
235845
235846
235847
235848
235849
235850
235851
235852
复制代码

能够顺序执行,没有出现问题

可重入锁

若是重入锁呢

public void a(){
    lock.lock();
    System.out.println("a");
    b();
    lock.unlock();
}

public void b(){
    lock.lock();
    System.out.println("b");
    lock.unlock();
}复制代码

在线程里执行a()方法

执行结果。打印完a以后就进入了等待。这个时候须要对MyLock进行优化

public class MyLock5 implements Lock {

    private boolean isLock = false ;

    private Thread nowThread = null ;

    private int threadNumber = 0 ;

    @Override
    public synchronized void lock() {
        Thread thread = Thread.currentThread();
        while (isLock && thread != nowThread ){
            try {
                wait(); //等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isLock = true ;
        nowThread = thread ;
        threadNumber++ ;
    }
    @Override
    public synchronized void unlock() {
        if (nowThread == Thread.currentThread()){
            threadNumber-- ;
            if (threadNumber == 0){
                notify(); //唤醒
                isLock = false ;
            }
        }
    }
}
复制代码

1:判断是不是同一个线程,若是是同一个线程的话进入等待状态,若是不是,继续执行

2:对线程进行计数

执行结果。a 方法执行完以后 b也执行

相关文章
相关标签/搜索