java基础之线程 Lock接口

栏目: Java · 发布时间: 5年前

内容简介:把java基础撸一边,从简单的开始。线程部分:抄了的网站:java并发编程-Lock

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

线程部分:

特别说明来源:

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

Lock的需要

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

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

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

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

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也执行


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C++ Primer 中文版(第 4 版)

C++ Primer 中文版(第 4 版)

Stanley B.Lippman、Josée LaJoie、Barbara E.Moo / 李师贤、蒋爱军、梅晓勇、林瑛 / 人民邮电出版社 / 2006 / 99.00元

本书是久负盛名的C++经典教程,其内容是C++大师Stanley B. Lippman丰富的实践经验和C++标准委员会原负责人Josée Lajoie对C++标准深入理解的完美结合,已经帮助全球无数程序员学会了C++。本版对前一版进行了彻底的修订,内容经过了重新组织,更加入了C++ 先驱Barbara E. Moo在C++教学方面的真知灼见。既显著改善了可读性,又充分体现了C++语言的最新进展和当......一起来看看 《C++ Primer 中文版(第 4 版)》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具