一、 synchronized的缺陷

当一个代码块被synchronized修饰时,同时该代码块被一个线程执行,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:

1)获取锁的线程执行完成代码块,自动释放锁资源

2)代码块中执行异常,由jvm释放锁资源

如果在执行代码块时候,一个线程在代码块执行过程中Thread.sleep() 睡眠  线程被阻塞了,其他线程只能等待当前线程执行完成后才能执行。及其浪费效率。

另外当多个线程在执行写与写操作时,会发生线程冲突,但当多个线程用于读操作,其中一个线程读取占用的锁资源  而其他线程只能等待造成浪费资源。

通过多个线程读取操作线程不会冲突,通过lock可以实现。

不同点:

synchronized是java内置的,是java关键字,lock 是一个接口  不是内置的通过这个接口可以实现同步访问

synchronized不需要用户手动释放锁资源,当同步方法或者同步代码块执行完成后,系统会自动让线程释放锁资源。而Lock必须要手动释放锁资源,如果不释放会出现死锁

二、 java.util.concurrent.locks包下常用的类

 1) Lock 是一个接口

提供了六个方法

void lock();    boolean tryLock(); boolean tryLock(long time,timeUnit unit); void  lockInteruptibly(); contition newContition()  void unlock();

其中lock()  tryLock()   tryLock(long time,timeUnit unit)  lockInteruptibly() 用于获取锁    unlock() 用于释放锁

由于采用lock  不会自动释放锁,需要手动释放锁  所以采用lock 必须在try{}catch(){}finally{}异常捕获中进行,在finally中释放锁

lock()是最常用的获取锁的方式

例子:

Lock lock = ..

lock.lock();

try{

   }catch(Exception e){

}finally{

    lock.unlock()

  }

tryLock 尝试获取锁,如果获取到返回true 如果获取不到返回false   不会拿不到锁一致在等待

tryLock(long time,TimeUnit unit) 与tryLock()一样都是尝试获取锁,如果获取到返回true  否则返回false  区别在于tryLock(long time ,TimeUnit unit)会等待一定时间,如果直接获取到锁返回true 或者在设置的等待时间内获取到锁返回true  否则返回flase

Lock lock = ..

if(lock.tryLock()){

  try{

  }catch(){

}finally{

   lock.unlock(); 

}

 }

lockInterruptibly() 可以用来获取锁,但是如果在获取的锁已经被其他线程锁占用  在等待过程中可以中断当前线程的等待状态。通俗的将  如果 a  b两个线程通过Lock.lockInterruptibly()获取某一个锁时,如果a先获取到了锁   b处于等待状态 那么b可以调用b.interrup()方法中断b的等待状态

由于lockInterruptibly()的声明中抛出了异常,所以lock.lockInterruptibly()必须放在try块中或者在调用lockInterruptibly()的方法外声明抛出InterruptedException。

public void method () throws InterruptedException{

  lock.Interruptibly();

try{

  }catch(){

}finally{

  lock.unlock();

}

 }

当一个线程获取到了锁 是不会被interrup()方法中断  只有处于等待状态的线程在才能被中断。

2)ReentrantLock  可重入锁

ReentrantLock是Lock接口的唯一实现类

Lock 接口的实现方式:

package cn.ac.bcc.lock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class LockDemo { private List<Integer> list = new ArrayList<>(); public static void main(String[] args) { //实例化当前类对象
final LockDemo ld = new LockDemo();
//创建两个线程对象 调用insert方法
new Thread(new Runnable(){
@Override
public void run() { ld.insert(Thread.currentThread()); } }).start(); new Thread(new Runnable(){ @Override
public void run() {
// TODO Auto-generated method stub
ld.insert(Thread.currentThread());
} }).start();
} public void insert(Thread thread){ //创建局部lock锁对象
Lock lock = new ReentrantLock();
System.out.println(lock);
//获取锁
lock.lock();
try {
for(int i=0;i<5;i++){
list.add(i);
}
System.out.println(Thread.currentThread().getName()+"获取了锁");
} catch (Exception e) {
// TODO: handle exception
}finally{
//释放锁
lock.unlock();
System.out.println(Thread.currentThread().getName()+"释放了锁");
}
} }

运行结果:

java.util.concurrent.locks.ReentrantLock@100363[Unlocked]
java.util.concurrent.locks.ReentrantLock@e0a386[Unlocked]
Thread-0获取了锁
Thread-1获取了锁
Thread-0释放了锁
Thread-1释放了锁

产生这种结果的原因: 当多个线程获取同一个对象的方法中的局部变量,每一个线程都会获取一个局部变量lock的副本   通过打印锁对象地址可以发现当前锁对象是不同的锁 所以他们可以获取不同的锁

解决这种方案:

将获取锁对象成员变量  属于当前对象

package cn.ac.bcc.lock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class LockDemo { private List<Integer> list = new ArrayList<>();
//创建局部lock锁对象
private Lock lock = new ReentrantLock(); public static void main(String[] args) { //实例化当前类对象
final LockDemo ld = new LockDemo();
//创建两个线程对象 调用insert方法
new Thread(new Runnable(){
@Override
public void run() { ld.insert(Thread.currentThread()); } }).start(); new Thread(new Runnable(){ @Override
public void run() {
// TODO Auto-generated method stub
ld.insert(Thread.currentThread());
} }).start();
} public void insert(Thread thread){ System.out.println(lock);
//获取锁
lock.lock();
try {
for(int i=0;i<5;i++){
list.add(i);
}
System.out.println(Thread.currentThread().getName()+"获取了锁");
} catch (Exception e) {
// TODO: handle exception
}finally{
//释放锁
lock.unlock();
System.out.println(Thread.currentThread().getName()+"释放了锁");
}
} }

运行结果:

java.util.concurrent.locks.ReentrantLock@bcda2d[Unlocked]
java.util.concurrent.locks.ReentrantLock@bcda2d[Locked by thread Thread-0]
Thread-0获取了锁
Thread-0释放了锁
Thread-1获取了锁
Thread-1释放了锁

tryLock()

package cn.ac.bcc.lock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class LockDemo { private List<Integer> list = new ArrayList<>();
//创建局部lock锁对象
private Lock lock = new ReentrantLock(); public static void main(String[] args) { //实例化当前类对象
final LockDemo ld = new LockDemo();
//创建两个线程对象 调用insert方法
new Thread(new Runnable(){
@Override
public void run() { ld.insert(Thread.currentThread()); } }).start(); new Thread(new Runnable(){ @Override
public void run() {
// TODO Auto-generated method stub
ld.insert(Thread.currentThread());
} }).start();
} public void insert(Thread thread){ System.out.println(lock);
//获取锁
if(lock.tryLock()){
try {
for(int i=0;i<5;i++){
list.add(i);
}
System.out.println(Thread.currentThread().getName()+"获取了锁");
} catch (Exception e) {
// TODO: handle exception
}finally{
//释放锁
lock.unlock();
System.out.println(Thread.currentThread().getName()+"释放了锁");
}
}else{
System.out.println(Thread.currentThread().getName()+"没有获取到锁");
} } }

运行结果:

java.util.concurrent.locks.ReentrantLock@14e8cee[Unlocked]
java.util.concurrent.locks.ReentrantLock@14e8cee[Locked by thread Thread-0]
Thread-1没有获取到锁
Thread-0获取了锁
Thread-0释放了锁

当多个线程获取同一个锁对象时,当线程a 获取锁  b尝试获取锁失败返回false

lockInterruptibly()

package cn.ac.bcc.lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class InterruptiblyDemo { Lock lock = new ReentrantLock(); public static void main(String[] args) { InterruptiblyDemo interruptiblyDemo = new InterruptiblyDemo(); MyThread myThread = new MyThread(interruptiblyDemo);
MyThread myThread2 = new MyThread(interruptiblyDemo);
myThread.start();
myThread2.start(); try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//中断线程2
myThread2.interrupt();
} public void insert() throws InterruptedException{
lock.lockInterruptibly();
try{
System.out.println(Thread.currentThread().getName()+"得到了锁");
long startTime = System.currentTimeMillis();
for(;;){ if(System.currentTimeMillis()-startTime>=Integer.MAX_VALUE){
break;
} }
}catch(Exception e){
e.printStackTrace();
}finally{
System.out.println(Thread.currentThread().getName()+"释放了锁");
lock.unlock();
}
}
}
class MyThread extends Thread{ InterruptiblyDemo interruptiblyDemo; public MyThread(InterruptiblyDemo interruptiblyDemo){
this.interruptiblyDemo=interruptiblyDemo;
} @Override
public void run(){
try {
interruptiblyDemo.insert();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(Thread.currentThread().getName()+"锁被中断");
}
} }

运行结果:

Thread-0得到了锁
java.lang.InterruptedException
Thread-1锁被中断
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:896)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1221)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:340)
at cn.ac.bcc.lock.InterruptiblyDemo.insert(InterruptiblyDemo.java:30)
at cn.ac.bcc.lock.MyThread.run(InterruptiblyDemo.java:60)

https://www.cnblogs.com/baizhanshi/p/6419268.html

同步锁之lock的更多相关文章

  1. Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)

    多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念.进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线 ...

  2. Java:多线程,使用同步锁(Lock)时利用Condition类实现线程间通信

    如果程序不使用synchronized关键字来保证同步,而是直接使用Lock对象来保证同步,则系统中不存在隐式的同步监视器,也就不能用wait().notify().notifyAll()方法进行线程 ...

  3. 多线程 - 线程同步锁(lock、Monitor)

    1. 前言 多线程编程的时候,我们不光希望两个线程间能够实现逻辑上的先后顺序运行,还希望两个不相关的线程在访问同一个资源的时候,同时只能有一个线程对资源进行操作,否则就会出现无法预知的结果. 比如,有 ...

  4. Java:多线程,线程同步,同步锁(Lock)的使用(ReentrantLock、ReentrantReadWriteLock)

    关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨Lock对象. synchronize ...

  5. 深入分析 Java Lock 同步锁

    前言 Java 的锁实现,有 Synchronized 和 Lock.上一篇文章深入分析了 Synchronized 的实现原理:由Java 15废弃偏向锁,谈谈Java Synchronized 的 ...

  6. 线程同步 synchronized 同步代码块 同步方法 同步锁

    一 同步代码块 1.为了解决并发操作可能造成的异常,java的多线程支持引入了同步监视器来解决这个问题,使用同步监视器的通用方法就是同步代码块.其语法如下: synchronized(obj){ // ...

  7. Java同步锁全息详解

    一 同步代码块 1.为了解决并发操作可能造成的异常,java的多线程支持引入了同步监视器来解决这个问题,使用同步监视器的通用方法就是同步代码块.其语法如下: synchronized(obj){ // ...

  8. Lock同步锁--线程同步

    Lock-同步锁 Lock是java5提供的一个强大的线程同步机制--通过显示定义同步锁对象来实现同步.Lock可以显示的加锁.解锁.每次只能有一个线程对lock对象加锁. Lock有ReadLock ...

  9. JUC--Callable 以及Lock同步锁

    /** * 一.创建执行线程的方式三:实现Callable接口.相较于实现Runnable接口方式,方法可以有返回值,并且可以抛出异常 * 二.callable 需要FutureTask实现类的支持. ...

随机推荐

  1. 从零开始的全栈工程师——js篇2.14(表单与计时器)

    一.表单 Form input select textarea type=”radio/checkbox/password/button/text/submit/reset/” 表单的事件 oncha ...

  2. Flash图表控件FusionCharts调整图表百分比大小

    用户可以为图表的宽度和高度设置百分比值,用来替代绝对的像素值. 以百分比的方式调整图表,首先需要更新HTML代码,如下所示: <div id="chartContainer" ...

  3. jquery的trigger和triggerHandler区别

    网上关于这个问题都是抄来抄去的,都没怎么说清楚.所以自己做了个测试,供大家参考指教.首先先看API怎么说的 为了检验一下,编写了一个简单的测试代码,如下: <html lang="en ...

  4. Git 推送和删除标签

    事实上Git 的推送和删除远程标签命令是相同的,删除操作实际上就是推送空的源标签refs:git push origin 标签名相当于git push origin refs/tags/源标签名:re ...

  5. jenkins代码自动部署

    jenkins是一个广泛用于持续构建的可视化web工具,持续构建说得更直白点,就是各种项目的"自动化"编译.打包.分发部署.jenkins可以很好的支持各种语言(比如:java, ...

  6. 还在用SELECT COUNT统计数据库表的行数?Out了

    在ABAP里我们如果想用代码获得一个数据库表里有多少条记录,常规做法是使用SELECT COUNT. 如果您使用的是HANA数据库,现在有一种新的办法可以达到同样的目的.HANA数据库里有一张名为m_ ...

  7. git入门使用摘录

    无论使用github或者gitlab,第一步都是在本地生产ssh-key,ssh-key作为客户端的身份证存放在user用户的.ssh文件夹下.如果之前没有生产过,需要用ssh-keygen命令生成. ...

  8. 问题 F: 等比数列

    问题 F: 等比数列 时间限制: 1 Sec  内存限制: 64 MB提交: 2699  解决: 1214[提交][状态][讨论版][命题人:外部导入] 题目描述 已知q与n,求等比数列之和: 1+q ...

  9. 2018.6.15 Java对象序列化详解

    一.定义 Serializable 序列化:把Java对象转换为字节序列的过程. 反序列化:把字节序列恢复为Java对象的过程. ObjectOutputStream对象输出流 可以将实现了Seria ...

  10. mongdb 一些操作

    一.命令操作数据库1.管理员身份打开cmd2.进到mongdb的mongo.exe文件所在路径3.show dbs 查看mongodb4.连接远程数据库:mongo ip:端口/数据库5.打开某个数据 ...