JAVA基础知识|synchronized和lock
一、synchronized
是jvm的一个关键字,使用过程均由jvm控制
有三种使用方式:
- 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
- 修饰代码块,同方法
- 修饰静态方法,作用于当前类加锁,进入同步代码前要获得当前类对象的锁
1.1、实例方法
作用于实例,会阻塞其他线程访问本实例,但不会影响其他线程访问其他实例
如果实例中有多个synchronized修饰的方法,当其中一个方法被访问时,其他方法也不可以被访问,所以我们在用synchronized关键字的时候,能缩小代码段的范围就尽量缩小,能在代码段上加同步就不要再整个方法上加同步
【示例】
import java.util.concurrent.TimeUnit; /**
* Created by jyy on 2018/6/21.
*/
public class SyncTest { public synchronized void test1(){
System.out.println("test1");
try {
TimeUnit.SECONDS.sleep(10);
}catch(InterruptedException ie){
System.out.println("中断异常");
}
System.out.println("test1");
} public synchronized void test2(){
System.out.println("test2");
} public void test3(){
System.out.println("test3");
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* Created by jyy on 2018/4/19.
*/
public class Test { public static void main(String[] args){
//需要声明为final类型
final SyncTest syncTest = new SyncTest();
//线程池
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(new Runnable() {
@Override
public void run() {
syncTest.test1();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
syncTest.test2();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
syncTest.test3();
}
});
}
}
执行结果:
test1
test3
test1
test2
1.2、代码块
作用于实例,同上
【示例】
//新增三个方法
public void test4(){
System.out.println("test4");
synchronized(this){
try {
TimeUnit.SECONDS.sleep(10);
}catch(InterruptedException ie){
System.out.println("中断异常");
}
System.out.println("test4");
}
} public void test5(){
System.out.println("test5");
synchronized(this){
System.out.println("test5");
}
} public void test6(){
System.out.println("test6");
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* Created by jyy on 2018/4/19.
*/
public class Test { public static void main(String[] args){
//需要声明为final类型
final SyncTest syncTest = new SyncTest();
//线程池
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(new Runnable() {
@Override
public void run() {
syncTest.test4();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
syncTest.test5();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
syncTest.test6();
}
});
}
}
执行结果:
test4
test5
test6
test4
test5
从执行结果上,可以看出,当访问关键字synchronized修饰的代码块时,其他synchronized修饰的代码块也会被锁住
1.3、静态方法
作用于类,会阻塞其他线程访问本类的同步方法,即使是不同的实例也不行
【示例】
//新增方法
public synchronized static void test7(){
int random= (new Random()).nextInt(100);
System.out.println(random);
try {
TimeUnit.SECONDS.sleep(10);
}catch(InterruptedException ie){
System.out.println("中断异常");
}
System.out.println(random);
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* Created by jyy on 2018/4/19.
*/
public class Test { public static void main(String[] args){
//线程池
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(new Runnable() {
@Override
public void run() {
SyncTest.test7();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
SyncTest.test7();
}
});
}
}
执行结果:
69
69
67
67
二、lock
Lock是一个接口,其中lock()、lockInterruptibly()、tryLock()、tryLock(long time, TimeUnit unit)方法可以获取锁,unlock()用来释放锁
如果采用Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。
2.1、ReentrantLock
ReentrantLock是实现了Lock接口的类,通过它,我们来看下四种获取锁方法的区别
2.1.1、lock()
【示例1】
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* Created by jyy on 2018/6/25.
*/
public class ReentrantLockTest {
private Lock lock = new ReentrantLock();//需要声明为全局变量 public void test1(){
lock.lock();//获取锁
try {
System.out.println(Thread.currentThread()+"得到了锁");
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
System.out.println("发生异常");
}finally {
System.out.println(Thread.currentThread()+"释放了锁");
lock.unlock();
}
}
}
//线程池
ExecutorService executorService = Executors.newCachedThreadPool();
final ReentrantLockTest reentrantLockTest = new ReentrantLockTest();
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantLockTest.test1();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantLockTest.test1();
}
});
执行结果:
Thread[pool-1-thread-1,5,main]得到了锁
Thread[pool-1-thread-1,5,main]释放了锁
Thread[pool-1-thread-2,5,main]得到了锁
Thread[pool-1-thread-2,5,main]释放了锁
【示例2】
//线程池
ExecutorService executorService = Executors.newCachedThreadPool();
final ReentrantLockTest reentrantLockTest = new ReentrantLockTest();
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantLockTest.test1();
}
});
final ReentrantLockTest reentrantLockTest1 = new ReentrantLockTest();
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantLockTest1.test1();
}
});
执行结果:
Thread[pool-1-thread-1,5,main]得到了锁
Thread[pool-1-thread-2,5,main]得到了锁
Thread[pool-1-thread-1,5,main]释放了锁
Thread[pool-1-thread-2,5,main]释放了锁
示例2说明Lock锁住的是实例,而不是类
2.1.2、tryLock()
tryLock()尝试获取锁,获取不到返回false,不影响代码继续执行
【示例】
//新增方法
public void test2(){
if(lock.tryLock())//获取锁
{
try {
System.out.println(Thread.currentThread() + "得到了锁");
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
System.out.println("发生异常");
} finally {
System.out.println(Thread.currentThread() + "释放了锁");
lock.unlock();
}
}else{
System.out.println(Thread.currentThread() + "获取锁失败");
}
}
//线程池
ExecutorService executorService = Executors.newCachedThreadPool();
final ReentrantLockTest reentrantLockTest = new ReentrantLockTest();
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantLockTest.test2();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantLockTest.test2();
}
});
执行结果:
Thread[pool-1-thread-1,5,main]得到了锁
Thread[pool-1-thread-2,5,main]获取锁失败
Thread[pool-1-thread-1,5,main]释放了锁
2.1.3、tryLock(long time, TimeUnit unit)
【示例】
//新增方法
public void test3() throws InterruptedException {
if(lock.tryLock(10,TimeUnit.SECONDS))//获取锁
{
try {
System.out.println(Thread.currentThread() + "得到了锁");
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
System.out.println("发生异常");
} finally {
System.out.println(Thread.currentThread() + "释放了锁");
lock.unlock();
}
}else{
System.out.println(Thread.currentThread() + "获取锁失败");
}
}
//线程池
ExecutorService executorService = Executors.newCachedThreadPool();
final ReentrantLockTest reentrantLockTest = new ReentrantLockTest();
executorService.execute(new Runnable() {
@Override
public void run() {
try {
reentrantLockTest.test3();
}catch(InterruptedException ie){
System.out.println("发生异常");
}
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
try {
reentrantLockTest.test3();
}catch(InterruptedException ie){
System.out.println("发生异常");
}
}
});
执行结果:
Thread[pool-1-thread-1,5,main]得到了锁
Thread[pool-1-thread-1,5,main]释放了锁
Thread[pool-1-thread-2,5,main]得到了锁
Thread[pool-1-thread-2,5,main]释放了锁
尝试10s获取锁,获取不到才会返回false
2.1.4、lockInterruptibly()
【示例】
//新增方法
public void test4() throws InterruptedException {
lock.lockInterruptibly();
try {
System.out.println(Thread.currentThread()+"得到了锁");
TimeUnit.SECONDS.sleep(10);
} catch (Exception e) {
System.out.println("中断成功");
}finally {
System.out.println(Thread.currentThread()+"释放了锁");
lock.unlock();
}
}
final ReentrantLockTest reentrantLockTest = new ReentrantLockTest();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
reentrantLockTest.test4();
}catch(InterruptedException ie){
System.out.println("发生异常");
}
}
},"1");
thread1.start();
try {
TimeUnit.SECONDS.sleep(3);
} catch (Exception e) {
System.out.println("延迟5s");
}
System.out.println("开始中断");
thread1.interrupt();//中断thread1
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
reentrantLockTest.test4();
}catch(InterruptedException ie){
System.out.println("发生异常");
}
}
},"2");
thread2.start();
执行结果:
Thread[1,5,main]得到了锁
开始中断
中断成功
Thread[1,5,main]释放了锁
Thread[2,5,main]得到了锁
Thread[2,5,main]释放了锁
成功中断thread1的锁
三、读写锁
3.1、ReadWriteLock
ReadWriteLock是一个接口,只包含两个方法readLock()、writeLock()
3.2、ReentrantReadWriteLock
ReentrantReadWriteLock实现了ReadWriteLock接口,下面主要说一下ReadLock()、WriteLock()两个方法
【示例1】
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock; /**
* Created by jyy on 2018/6/26.
*/
public class ReentrantReadWriteLockTest { private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); /**
* 读锁
*/
public void test1(){
rwl.readLock().lock();
try {
System.out.println(Thread.currentThread() + "得到了读锁");
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
System.out.println("发生异常");
} finally {
System.out.println(Thread.currentThread() + "释放了读锁");
rwl.readLock().unlock();
}
} /**
* 写锁
*/
public void test2(){
rwl.writeLock().lock();
try {
System.out.println(Thread.currentThread() + "得到了写锁");
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
System.out.println("发生异常");
} finally {
System.out.println(Thread.currentThread() + "释放了写锁");
rwl.writeLock().unlock();
}
} }
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* Created by jyy on 2018/4/19.
*/
public class Test { public static void main(String[] args) throws InterruptedException {
final ReentrantReadWriteLockTest reentrantReadWriteLockTest = new ReentrantReadWriteLockTest();
ExecutorService executorService = Executors.newCachedThreadPool();//连接池
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantReadWriteLockTest.test1();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantReadWriteLockTest.test1();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantReadWriteLockTest.test1();
}
});
}
}
执行结果:
Thread[pool-1-thread-1,5,main]得到了读锁
Thread[pool-1-thread-2,5,main]得到了读锁
Thread[pool-1-thread-3,5,main]得到了读锁
Thread[pool-1-thread-3,5,main]释放了读锁
Thread[pool-1-thread-1,5,main]释放了读锁
Thread[pool-1-thread-2,5,main]释放了读锁
多个线程都可以获取到读锁
【示例2】
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantReadWriteLockTest.test1();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantReadWriteLockTest.test1();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantReadWriteLockTest.test2();
}
});
执行结果:
Thread[pool-1-thread-1,5,main]得到了读锁
Thread[pool-1-thread-2,5,main]得到了读锁
Thread[pool-1-thread-2,5,main]释放了读锁
Thread[pool-1-thread-1,5,main]释放了读锁
Thread[pool-1-thread-3,5,main]得到了写锁
Thread[pool-1-thread-3,5,main]释放了写锁
访问写锁时,必须等读锁全部释放
【示例3】
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantReadWriteLockTest.test2();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantReadWriteLockTest.test1();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
reentrantReadWriteLockTest.test2();
}
});
执行结果:
Thread[pool-1-thread-1,5,main]得到了写锁
Thread[pool-1-thread-1,5,main]释放了写锁
Thread[pool-1-thread-2,5,main]得到了读锁
Thread[pool-1-thread-2,5,main]释放了读锁
Thread[pool-1-thread-3,5,main]得到了写锁
Thread[pool-1-thread-3,5,main]释放了写锁
想要获取读锁,必须先等到写锁释放
总结:
1、如果一个线程占用了读锁,其他线程依然可以获取到这个读锁,但不可以获取到写锁
2、如果一个线程占用了写锁,其他线程不可以获取到读锁和写锁
四、synchronized与lock的区别
1)synchronized是java的一个关键字,而Lock是一个接口
2)synchronized发生异常,会自动释放占有的锁,而Lock必须要主动释放锁,否则会一直处于占用状态
3)Lock中的lockInterruptibly()可以响应中断,而synchronized不可以
4)Lock中的tryLock()可以尝试获取锁,判断是否成功获取到锁,而synchronized不可以
5)ReentrantReadWriteLock可以声明读写锁,提高查询效率
两者不是非一即二的存在,具体使用要看不同的场景
五、锁类型
可重入锁:在执行对象中所有同步方法不用再次获得锁
举个简单的例子,当一个线程执行到某个synchronized方法时,比如说method1,而在method1中会调用另外一个synchronized方法method2,此时线程不必重新去申请锁,而是可以直接执行方法method2
synchronized和ReentrantLock都是可重入锁
可中断锁:在等待获取锁过程中可中断,如ReentrantLock中的lockInterruptibly()
公平锁: 按等待获取锁的线程的等待时间进行获取,等待时间长的具有优先获取锁权利
ReentrantLock默认是非公平锁,可以通过new ReentrantLock(true)声明为公平锁
读写锁:对资源读取和写入的时候拆分为两部分处理,读的时候可以多线程一起读,写的时候必须同步地写,如ReentrantReadWriteLock
JAVA基础知识|synchronized和lock的更多相关文章
- java基础: synchronized与Lock的区别
主要区别 1. 锁机制不一样:synchronized是java内置关键字,是在JVM层面实现的,系统会监控锁的释放与否,lock是JDK代码实现的,需要手动释放,在finally块中释放.可以采用非 ...
- Java基础知识回顾之七 ----- 总结篇
前言 在之前Java基础知识回顾中,我们回顾了基础数据类型.修饰符和String.三大特性.集合.多线程和IO.本篇文章则对之前学过的知识进行总结.除了简单的复习之外,还会增加一些相应的理解. 基础数 ...
- Java基础知识总结(超级经典)
Java基础知识总结(超级经典) 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java ...
- 毕向东—Java基础知识总结(超级经典)
Java基础知识总结(超级经典) 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java ...
- 沉淀,再出发:Java基础知识汇总
沉淀,再出发:Java基础知识汇总 一.前言 不管走得多远,基础知识是最重要的,这些知识就是建造一座座高楼大厦的基石和钢筋水泥.对于Java这门包含了编程方方面面的语言,有着太多的基础知识了,从最初的 ...
- java基础知识一览(二)
一.java基础知识 1.一个文件中只能有一个public的类,因为他的类名要求和文件名相同. 2.classpath变量可以设置其它目录下的类. 例如:类文件所在目录是:F:\Javajdk,那么没 ...
- 黑马毕向东Java基础知识总结
Java基础知识总结(超级经典) 转自:百度文库 黑马毕向东JAVA基础总结笔记 侵删! 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部 ...
- java基础知识小总结【转】
java基础知识小总结 在一个独立的原始程序里,只能有一个 public 类,却可以有许多 non-public 类.此外,若是在一个 Java 程序中没有一个类是 public,那么该 Java 程 ...
- Java 基础知识(一)
Java基础知识篇: 一.关键字解释 1. final:修饰非抽象类,非抽象方法和属性, 以及修饰方法参数,代表“无法改变的”.出于对设计或者效率的考虑使用该关键字. final类无法被继承,fina ...
随机推荐
- 【js】字符串反转(倒序)的多种处理方式
今天发布一篇关于字符串反转的几种方式(一种问题的解决方案不是只有一种). 方式1: 这种方式比较简单,推荐使用 字符串转数组,反转数组,数组转字符串. split(""):根据空字 ...
- 发现一个对列排版挺好用的命令:column
help [root@hdpool1 tmp]# column -h Usage: column [options] [file ...] Options: -c, --columns <wid ...
- Linux的desktop文件正常编写赋权,仍无法打开解决办法
Linux的desktop文件正常编写赋权,仍无法打开解决办法 如果你像我一样遇到了这个问题, 明明都没有问题, desktop文件不显示图标, 双击打开是文本编辑器, 同时也有执行权限 打开却是这样 ...
- 温控PID自测验程序
#pragma once #ifndef _PID_H_ #define _PID_H_ #include <vector> #include <map> using name ...
- 日期时间格式化 SimpleDateFormat与DateTimeFormatter
原文:https://www.jianshu.com/p/b212afa16f1f 1.SimpleDateFormat为什么不是线程安全的? 如果我们把SimpleDateFormat定义成stat ...
- 2019-ACM-ICPC-沈阳区网络赛-K. Guanguan's Happy water-高斯消元+矩阵快速幂
2019-ACM-ICPC-沈阳区网络赛-K. Guanguan's Happy water-高斯消元+矩阵快速幂 [Problem Description] 已知前\(2k\)个\(f(i)\),且 ...
- C++11新特性之operator "" xxx(const char *, size_t n)
从C++11开始,我们可以使用以下形式通过常量字符串构造自定义类型, 比如: class Person { public: Person(const std::string& name): _ ...
- idea中tomcat的On Upate Action 与 On Frame Deactivation配置
On Upate Action 与 On Frame Deactivation 这两个选项的设置,依赖于项目的部署方式 是war包 还是 exploded , 只讲exploded模式下的设置,因为 ...
- 移动端自适应js
window.addEventListener('resize', setHtmlFontSize) setHtmlFontSize(); function setHtmlFontSize() { v ...
- 前端学习笔记--CSS布局--float定位
1.float属性 box1向右移动,box2顶替了box1的位置,box3顶替了box2的位置. 2.clear属性 案例: 一列三行布局: <!DOCTYPE html> <ht ...