java api trylock_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也执行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值