JAVA锁机制之-LOCK锁

时间:2021-11-21 14:12:10

java中有个两种锁,第一种是synchronize锁(之前已经讲过),现在来研究一下LOCK锁。

下面看个测试:

测试类:




public class Test {

static Print print = new Print();

static Thread1 thread1 = new Thread1();

static Thread2 thread2 = new Thread2();

public static void main(String[] args) {
new Thread(thread1).start();
new Thread(thread2).start();
}

public static class Thread1 implements Runnable{

@Override
public void run() {
System.out.println("this is first thread start");
print.print();
System.out.println("this is first thread end");
}

}

public static class Thread2 implements Runnable{

@Override
public void run() {
System.out.println("this is sencond thread start");
print.print();
System.out.println("this is sencond thread end");
}

}



}

打印类;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class Print {

Lock lock = new ReentrantLock();


public void print(){
lock.lock();
System.out.println("print....");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
lock.unlock();
}


}

输出:

this is first thread start
this is sencond thread start
print....(运行到print()方法的时候锁住代码块,如果没有锁住另一个线程也会输出print...这个需要读者根据代码逻辑自己想清楚)
this is first thread end
print....
this is sencond thread end


下面把lock去掉,如下:

打印类:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class Print {

Lock lock = new ReentrantLock();


public void print(){
System.out.println("print....");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}


}

测试类和上面相同就不贴了

输出:

this is first thread start
print....
this is sencond thread start
print....
this is sencond thread end
this is first thread end


结论:lock锁确实有锁住在lock()方法和unlock()方法之间的代码块的功能,即能够实现线程安全(同步)。



下面,进一步探究,看源码:

public interface Lock {


void lock();


void lockInterruptibly() throws InterruptedException;


boolean tryLock();


boolean tryLock(long time, TimeUnit unit) throws InterruptedException;


void unlock();


Condition newCondition();
}

我把注释给删除了(因为我希望我的博客用最简洁,最通俗易懂的方式提供给读者,而把不需要和不重要的东西全部删除,短小精悍!)


上面可以看出,有很多方法,我们一一来做实验:


1.lock()   -----上文已经给出例子,这里不再阐述


2. tryLock()    -------分为有参和无参

在探究tryLock()的时候,我犯了两个错误

第一个错误;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class Print {

Lock lock = new ReentrantLock();


public void print(){
boolean isLock = lock.tryLock();
System.out.println("print...."+isLock);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
lock.unlock();
}


}


 输出:

at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:127)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1175)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:431)
at Print.print(Print.java:19)
at Test$Thread2.run(Test.java:34)
at java.lang.Thread.run(Thread.java:619)

原因是因为没有lock()就直接unlock(),所以报错

接下来,改成:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class Print {

Lock lock = new ReentrantLock();


public void print(){
boolean isLock = lock.tryLock();
System.out.println("print...."+isLock);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (isLock) lock.unlock();
}


}

输出:

this is first thread start
this is sencond thread start
print....true
print....false
this is sencond thread end
this is first thread end

奇怪!为何打印结果没有锁住,两个第一个线程的print()还没有执行完,就执行了第二个线程的Print()!

因为这是错误的用法!

最后查阅源码的demo,发现应该这么用:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class Print {

Lock lock = new ReentrantLock();


public void print(){
if(lock.tryLock()){
System.out.println("print....");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
lock.unlock();
}
}


}


}


输出:

this is first thread start
this is sencond thread start
print....
this is sencond thread end
this is first thread end

这样才有效,你需要将tryLock()方法放在IF()条件中判断!

另外,注意一点,Unlock()方法要放在finally里面,不然又会发生我第一个错误!

有参数的tryLock()就是用来给定一个时间,如果参数里面规定的时间内没有取到这个锁,那么,就会放弃请求资源。有参数的tryLock()在实际工作中非常有用。


3.下面就是牛逼的lockInterruptibly()方法了,测试如下:

使用lock

打印类:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class Print {

Lock lock = new ReentrantLock();


public void print(){
try {
lock.lock();
System.out.println("print....");
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
lock.unlock();
}
}




}

测试类:




public class Test {

static Print print = new Print();

static Thread1 thread1 = new Thread1();

static Thread2 thread2 = new Thread2();

public static void main(String[] args) {
Thread t1 = new Thread(thread1);
t1.start();
Thread t2 = new Thread(thread2);
t2.start();
t1.interrupt();//注意加了这句
}

public static class Thread1 implements Runnable{

@Override
public void run() {
System.out.println("this is first thread start");
print.print();
System.out.println("this is first thread end");
}

}

public static class Thread2 implements Runnable{

@Override
public void run() {
System.out.println("this is sencond thread start");
print.print();
System.out.println("this is sencond thread end");
}

}



}


输出;


this is first thread start
print....
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at Print.print(Print.java:14)
at Test$Thread1.run(Test.java:26)
at java.lang.Thread.run(Thread.java:619)
this is sencond thread start
this is first thread end
print....
this is sencond thread end

你可以发现线程1并没有因此而中断(这里需要用到interrupt()这个方法的知识,这个方法只有在线程发生wait,sleep,join三种阻塞情况下时才会中断线程,具体如何使用请查阅相关资料或者在我博客下面留言,我会回答你们的提问)

下面换成lockInterruptibly():

打印类:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class Print {

Lock lock = new ReentrantLock();


public void print(){
try {
lock.lockInterruptibly();
System.out.println("print....");
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
lock.unlock();
}
}




}

测试类和上面Lock()的一样,就不贴了。


输出:

this is first thread start
this is sencond thread start
print....
java.lang.InterruptedException
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1135)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:312)
at Print.print(Print.java:12)
at Test$Thread1.run(Test.java:26)
at java.lang.Thread.run(Thread.java:619)
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:127)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1175)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:431)
at Print.print(Print.java:20)
at Test$Thread1.run(Test.java:26)
at java.lang.Thread.run(Thread.java:619)
this is sencond thread end


并没有出现第一个线程打印的 print... 和this is first thread end,说明第一个线程中断了。


我想此刻你已经知道

结论:lockInterruptibly()在阻塞时会中断线程,而lock()不会!



4. Condition newCondition();

这个相当于object.await()和object.notify(),但是比object的更好用,现在就不详细说明了,以后有时间再补充。



总结:Lock()用于强制性的锁定,不可中断线程,一定会阻塞直到获得锁;tryLock()放在if条件里面,后面可以接时间参数;interrupteLock()可以中断线程;condition和Objct的wait()和notify()类似,可以阻塞和唤醒线程;



如果你觉得本文不错,点赞+关注~

谢谢!