Lock
Lock与Synchronized区别
- Lock非Java内置特性,而Synchronized是Java语言的关键字,因此是内置特性。Lock是一个接口,通过这个接口可以实现同步访问。
- Synchronized不需要手动释放锁,当Synchronized方法或代码块执行完成后,系统会自动让线程释放对锁的占用;Lock需要用户手动释放锁,如果没有释放锁,会导致死锁现象。
Lock接口的使用
public interface lock {
void lock();
void lockInterruptibly() throws InterruptException;
boolean trylock();
boolean trylock(long time, TimeUnit unit) throws InterruptException;
void unlock();
Condition newCondition();
}
unlock()作用是释放锁。最常用获取锁的方法是lock(),lock必须被显式的被创建,锁定和释放。一般使用ReentrantLock实例化,为了保证锁最后一定释放,要把互斥区放到try块中,并在finally语句中释放锁。当有return语句时,把return语句放到try子句中,确保unlock()不会过早执行。
//默认为非公平锁,若使用公平所,需要传入参数true
Lock lock = new ReentrantLock();
···
lock.lock();
try{
//执行任务,更新状态
} catch(Exception e){
...
} finally{
lock.unlock();
}
tryLock()返回值是布尔型,trylock(long time, TimeUnit unit)方法和tryLock()类似,区别就是这个方法拿不到锁会等待一段时间,如果在时间期限内还拿不到锁就返回false。
Lock lock = new ReentrantLock();
···
if(lock.tryLock()){
try{
//执行任务,更新状态
}catch(Exception e){
···
} finally{
lock.unlock();
}
}else{
···
}
lockInterruptibly()与以上方法不同,这个方法获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程等待状态。例如:线程A,线程B都想获取到锁,此时A获取到锁,B只能等待,但是B也可以调用threadB.interrupt()中断等待状态。
public void method() throws InterruptedException(){
lock.interruptibly();
try{
//执行任务,更新状态
}catch(Exception e){
···
} finally{
lock.unlock();
}
}
已获取到锁的线程无法interrupt()中断,interrupt()只能中断阻塞状态的线程。
以上是简略的用法,完整的使用方法如下:
对lock()方法执行代码如下:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Stream;
public class Main{
private List<Integer> list = new ArrayList<>();
(1)//private Lock lock = new ReentrantLock();
public void method(Thread thread){
(2)//Lock lock = new ReentrantLock();
lock.lock();
try{
System.out.println(thread.getName()+"获取线程");
Stream.of(1,2,3,4,5).forEach(e -> list.add(e));
System.out.println(list);
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println(thread.getName()+"释放线程");
lock.unlock();
}
}
public static void main(String[] args) {
Main test = new Main();
new Thread(){
@Override
public void run(){
super.run();
test.method(Thread.currentThread());
}
}.start();
new Thread(){
@Override
public void run() {
super.run();
test.method(Thread.currentThread());
}
}.start();
}
}
若是去掉(2)处注释,执行代码,执行结果如下:
Thread-0获取线程
Thread-1获取线程
[null, 1, 2, 2, 3, 3, 4, 5, 5]
[null, 1, 2, 2, 3, 3, 4, 5, 5]
Thread-1释放线程
Thread-0释放线程
为何Thread-0还未释放,Thread-1就获取到锁了呢?因为注释(2)处的lock是局部变量,我们两个线程执行时获取到的lock锁不是同一个锁,所以没有冲突。而(1)处的lock是仅此一家啊!
所以去掉(1)处的注释获取到的结果如下:
Thread-0获取线程
[1, 2, 3, 4, 5]
Thread-0释放线程
Thread-1获取线程
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
Thread-1释放线程
下面对tryLock()方法执行代码如下:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Stream;
public class Main{
private List<Integer> list = new ArrayList<Integer>();
private Lock lock = new ReentrantLock();
public void method(Thread thread){
if(lock.tryLock()){
try{
System.out.println(thread.getName()+"获取线程");
Stream.of(1,2,3,4,5).forEach(e -> list.add(e));
System.out.println(list);
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println(thread.getName()+"释放线程");
lock.unlock();
}
}else{
System.out.println(thread.getName()+"获取线程失败");
}
}
public static void main(String[] args) {
Main test = new Main();
new Thread(){
@Override
public void run(){
super.run();
test.method(Thread.currentThread());
}
}.start();
new Thread(){
@Override
public void run() {
super.run();
test.method(Thread.currentThread());
}
}.start();
}
}
tryLock()执行结果如下:
Thread-1获取线程
Thread-0获取线程失败
[1, 2, 3, 4, 5]
Thread-1释放线程
对lockInterruptibly执行测试代码如下:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Stream;
class thread1 implements Runnable{
private Main test = null;
public thread1(Main test){
this.test = test;
}
@Override
public void run() {
try{
test.method(Thread.currentThread());
}catch(Exception e){
System.out.println(Thread.currentThread()+"线程被中断");
}
}
}
public class Main{
Lock lock = new ReentrantLock();
public void method(Thread thread) throws InterruptedException{
lock.lockInterruptibly();
try{
System.out.println(thread.getName()+"得到了锁");
long startTime = System.currentTimeMillis();
for( ; ;) {
if(System.currentTimeMillis() - startTime >= Integer.MAX_VALUE)
break;
}
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println(thread.getName()+"释放线程");
lock.unlock();
}
}
public static void main(String[] args) {
Main test = new Main();
Thread thread_1 = new Thread(new thread1(test));
Thread thread_2 = new Thread(new thread1(test));
thread_1.start();
thread_2.start();
try{
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
thread_2.interrupt();
}
}
执行结果如下所示:
Thread-0得到了锁
Thread[Thread-1,5,main]线程被中断
ReadWriteLock接口
public interface ReadWriteLock{
//return the lock of userd for reading
Lock readLock();
//return the lock of userd for writing
Lock writeLock();
}
这个接口的两个方法主要用来获取读锁和获取写锁。ReentrantReadWriteLock实现这个接口,并且包含其他很多方法,最主要的还是readLock()和writeLock().这样的用意还是让多个线程可以同时进行读操作.
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class test {
private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
public static void main(String[] args) {
test _test = new test();
new Thread(){
@Override
public void run() {
super.run();
_test.method(Thread.currentThread());
}
}.start();
new Thread(){
@Override
public void run() {
super.run();
_test.method(Thread.currentThread());
}
}.start();
}
public void method(Thread thread){
reentrantReadWriteLock.readLock().lock();
long start = System.currentTimeMillis();
try{
while(System.currentTimeMillis()-start<1){
System.out.println(thread.getName()+"正在读操作");
}
System.out.println(thread.getName()+"都操作完成");
}catch(Exception e){
e.printStackTrace();
}finally {
reentrantReadWriteLock.readLock().unlock();
}
}
}
总结来说,Lock和synchronized有以下几点不同:
- Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
- synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
- Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
- 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
- Lock可以提高多个线程进行读操作的效率。
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
Lock
Lock与Synchronized区别
Lock接口的使用
unlock()作用是释放锁。最常用获取锁的方法是lock(),lock必须被显式的被创建,锁定和释放。一般使用ReentrantLock实例化,为了保证锁最后一定释放,要把互斥区放到try块中,并在finally语句中释放锁。当有return语句时,把return语句放到try子句中,确保unlock()不会过早执行。
tryLock()返回值是布尔型,trylock(long time, TimeUnit unit)方法和tryLock()类似,区别就是这个方法拿不到锁会等待一段时间,如果在时间期限内还拿不到锁就返回false。
lockInterruptibly()与以上方法不同,这个方法获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程等待状态。例如:线程A,线程B都想获取到锁,此时A获取到锁,B只能等待,但是B也可以调用threadB.interrupt()中断等待状态。
已获取到锁的线程无法interrupt()中断,interrupt()只能中断阻塞状态的线程。
以上是简略的用法,完整的使用方法如下:
对lock()方法执行代码如下:
若是去掉(2)处注释,执行代码,执行结果如下:
为何Thread-0还未释放,Thread-1就获取到锁了呢?因为注释(2)处的lock是局部变量,我们两个线程执行时获取到的lock锁不是同一个锁,所以没有冲突。而(1)处的lock是仅此一家啊!
所以去掉(1)处的注释获取到的结果如下:
下面对tryLock()方法执行代码如下:
tryLock()执行结果如下:
对lockInterruptibly执行测试代码如下:
执行结果如下所示:
ReadWriteLock接口
这个接口的两个方法主要用来获取读锁和获取写锁。ReentrantReadWriteLock实现这个接口,并且包含其他很多方法,最主要的还是readLock()和writeLock().这样的用意还是让多个线程可以同时进行读操作.
总结来说,Lock和synchronized有以下几点不同:
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。