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()类似,可以阻塞和唤醒线程;
如果你觉得本文不错,点赞+关注~
谢谢!