Java synchronized关键字用法(清晰易懂)
本篇随笔主要介绍 java 中 synchronized 关键字常用法,主要有以下四个方面:
1、实例方法同步
2、静态方法同步
3、实例方法中同步块
4、静态方法中同步块
我觉得在学习synchronized关键字之前,我们首先需要知道以下一点:Java 中每个实例对象对应一把锁且每个实例对象只有一把锁,synchronized 关键字是通过对相应的实例对象加锁来实现同步功能的。
一、实例方法中使用 synchronized 加锁
实例方法中默认被加锁的对象是调用此方法的实例对象。
- class ImmutableValue {
- public synchronized void comeIn() throws InterruptedException{
- System.out.println(Thread.currentThread().getName() + ": start");
- Thread.sleep(5000);
- System.out.println(Thread.currentThread().getName() + ": finish");
- }
- public void synchronized comeInIn() throws InterruptedException {
- System.out.println(Thread.currentThread().getName() + ": start");
- Thread.sleep(5000);
- System.out.println(Thread.currentThread().getName() + ": finish");
- }
- }
- public class TestImmutableValue {
- public static void main(String[] args) {
- ImmutableValue im = new ImmutableValue();
- Thread t1 = new Thread(new Runnable() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- try {
- im.comeIn();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }, "t1");
- Thread t2 = new Thread(new Runnable() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- try {
- im.comeInIn();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }, "t2");
- t1.start();
- t2.start();
- }
- }
在上面的代码中创建了两个线程并分别命名为 t1, t2。调用了同一个对象 im 的两个同步方法 comeIn 和 comeInIn, 执行结果如下:
在 t1 线程开始执行后,即使 t1 线程睡眠了5s,线程 t2 中的 comeInIn 方法仍然没有得到执行。这是因为 t1 线程先执行的 comeIn 方法,持有了对象 im 的锁,且 comeIn 方法并没有执行完,对象 im 的锁没有被释放,所以 comeInIn 方法无法对对象 im 加锁,就无法继续执行,只能等到 t1 线程中的 comeIn 方法执行完毕,释放对象 im 的锁,comeInIn 方法才能继续执行。
但是如果 t1 线程调用的是对象 im 的 comeIn 方法,而 t2 线程调用的是我们声明的另外一个 ImmutableValue 对象 im2 对象的 comeInIn 方法,则这两个方法的执行是互不影响的。因为 t1 线程的 comeIn 方法要获得 im 对象的锁,而 t2 线程要获得的是 im2 对象的锁,两个锁并不是同一个锁(Java中每个实例对象都有且只有一个锁),所以这两个方法执行互不影响。
二、静态方法中使用 synchronized 加锁
静态方法中默认被加锁的对象是此静态方法所在类的 class 对象。
- class staticMethodSynchronized {
- public static synchronized void method1() throws InterruptedException {
- System.out.println(Thread.currentThread().getName() + ": start");
- Thread.sleep(5000);
- System.out.println(Thread.currentThread().getName() + ": finish");
- }
- public static synchronized void method2() throws InterruptedException {
- System.out.println(Thread.currentThread().getName() + ": start");
- Thread.sleep(5000);
- System.out.println(Thread.currentThread().getName() + ": finish");
- }
- }
- public class TestStaticClassSynchronized {
- public static void main(String[] args) {
- Thread t1 = new Thread(new Runnable() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- try {
- staticMethodSynchronized.method1();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }, "t1");
- Thread t2 = new Thread(new Runnable() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- try {
- staticMethodSynchronized.method2();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }, "t2");
- t1.start();
- t2.start();
- }
- }
在上述代码中创建了两个线程并命名为 t1,t2。 t1,t2 线程调用了 staticMethodSynchronized 类的两个静态同步方法 method1 和 method2。执行结果如下:
在 t1 线程开始执行后,即使 t1 线程睡眠了5s,线程 t2 中的 method2 方法仍然没有得到执行。这是因为 t1 线程先执行的 method1 方法,持有了staticMethodSynchronized 类对象的锁,且 method1 方法并没有执行完,staticMethodSynchronized 类对象的锁没有被释放,所以 comeInIn 方法无法对staticMethodSynchronized 类对象加锁,就无法继续执行,只能等到 t1 线程中的 method1 方法执行完毕,释放 staticMethodSynchronized 类对象的锁,method2 方法才能继续执行。
三、实例方法中使用 synchronized 关键字制造同步块
同步块中默认被加锁的对象是此同步块括号声明中包含的对象。
- class ImmutableValue {
- public synchronized void comeIn() throws InterruptedException{
- System.out.println(Thread.currentThread().getName() + ": start");
- Thread.sleep(5000);
- System.out.println(Thread.currentThread().getName() + ": finish");
- }
- public void comeInIn() throws InterruptedException {
- System.out.println(Thread.currentThread().getName() + ": start");
- synchronized(this) {
- }
- System.out.println(Thread.currentThread().getName() + ": finish");
- }
- }
- public class TestImmutableValue {
- public static void main(String[] args) {
- ImmutableValue im = new ImmutableValue();
- Thread t1 = new Thread(new Runnable() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- try {
- im.comeIn();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }, "t1");
- Thread t2 = new Thread(new Runnable() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- try {
- im.comeInIn();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }, "t2");
- t1.start();
- t2.start();
- }
- }
由以上代码可以看到: 在 comeInIn 方法中,运用 synchronized(this) 制造同步块,要执行同步块内的代码,就必须获得 this 对象的锁(调用 comeInIn 方法的对象)。
执行结果可能为:
由此执行结果可见:t1 线程先执行了 comeIn 方法,获得了对象 im 的锁,之后由于 t1 线程进入睡眠状态,t2 线程得到运行,开始执行 comeInIn 方法,当执行到同步代码块时发现对象 im 已被加锁,无法继续执行。t1 线程睡眠结束之后继续执行,结束后释放对象 im 的锁,t2 线程才能继续执行。
四、静态方法中使用 synchronized 关键字制造同步块
同步块中默认被加锁的对象是此同步块括号声明中包含的对象。
- class staticMethodSynchronized {
- private static final Object OBJ = new Object();
- public static void method1() throws InterruptedException {
- System.out.println(Thread.currentThread().getName() + ": start");
- synchronized(OBJ) {
- System.out.println(Thread.currentThread().getName() + ": 获得锁");
- System.out.println(Thread.currentThread().getName() + ": 释放锁");
- }
- System.out.println(Thread.currentThread().getName() + ": finish");
- }
- public static void method2() throws InterruptedException {
- System.out.println(Thread.currentThread().getName() + ": start");
- synchronized(OBJ) {
- System.out.println(Thread.currentThread().getName() + ": 获得锁");
- System.out.println(Thread.currentThread().getName() + ": 释放锁");
- }
- System.out.println(Thread.currentThread().getName() + ": finish");
- }
- }
- public class TestStaticClassSynchronized {
- public static void main(String[] args) {
- Thread t1 = new Thread(new Runnable() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- try {
- staticMethodSynchronized.method1();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }, "t1");
- Thread t2 = new Thread(new Runnable() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- try {
- staticMethodSynchronized.method2();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }, "t2");
- t1.start();
- t2.start();
- }
- }
在上述代码中,两个静态方法中的同步块都要获得对象 OBJ 的锁才能继续向下执行,执行结果可能如下:
若 t1 线程先获得锁,则必须等到 t1 释放锁之后,t2 线程中同步代码块及其之后的代码才能继续执行,t2 线程先获得锁,t1 线程同理。
总之,我认为我们只需抓住一点:Java 中每个实例对象对应一把锁且每个实例对象只有一把锁,synchronized 关键字是通过对相应的实例对象加锁来实现同步功能的(静态方法为对相应的 class 对象加锁)。在执行 synchronized 方法或 synchronized 同步块之前,我们只需判断其需要获得的对象的锁是否可获得,就可判断此方法或同步块是否可得到执行。
Java synchronized关键字用法(清晰易懂)的更多相关文章
- 巨人大哥谈Java中的Synchronized关键字用法
巨人大哥谈Java中的Synchronized关键字用法 认识synchronized 对于写多线程程序的人来说,经常碰到的就是并发问题,对于容易出现并发问题的地方价格synchronized基本上就 ...
- synchronized关键字用法
看到网上很多讲synchronized关键字用法的文章,说的都很有道理,也很深刻,但是看完总感觉脑袋里还是有点乱乱的.经过一番自己的思考后,想从自己的思考角度出发,来说一说synchronized关键 ...
- Java synchronized 关键字详解
Java synchronized 关键字详解 前置技能点 进程和线程的概念 线程创建方式 线程的状态状态转换 线程安全的概念 synchronized 关键字的几种用法 修饰非静态成员方法 sync ...
- Java Synchronized 关键字
本文内容 Synchronized 关键字 示例 Synchronized 方法 内部锁(Intrinsic Locks)和 Synchronization 参考资料 下载 Demo Synchron ...
- Java中的Synchronized关键字用法
认识synchronized 对于写多线程程序的人来说,经常碰到的就是并发问题,对于容易出现并发问题的地方加上synchronized修饰符基本上就搞定 了,如果说不考虑性能问题的话,这一招绝对能应对 ...
- Java:synchronized关键字引出的多种锁
前言 Java 中的 synchronized关键字可以在多线程环境下用来作为线程安全的同步锁.本文不讨论 synchronized 的具体使用,而是研究下synchronized底层的锁机制,以及这 ...
- java synchronized关键字浅探
synchronized 是 java 多线程编程中用于使线程之间的操作串行化的关键字.这种措施类似于数据库中使用排他锁实现并发控制,但是有所不同的是,数据库中是对数据对象加锁,而 java 则是对将 ...
- java synchronized关键字
引用其他人的一段话 Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchro ...
- Java synchronized关键字的理解
转载自:http://blog.csdn.net/xiao__gui/article/details/8188833 在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环 ...
随机推荐
- 初探Stage3D(二) 了解AGAL
关于本文 本文并无打算事无巨细的介绍一遍AGAL,仅仅是对现有文档的一些理解及汇总,所以请先阅读相参考文档 AGAL概念 参考资料 http://www.adobe.com/devnet/flashp ...
- saiku缓存整理
使用saiku的人,肯定都有这么一个经历,查询了一次多维分析数据表,第二次之后就特别快,因为它缓存了结果,可问题是过了一天,甚至几天,来源数据早都更换了,可还是这个缓存结果.问题来了,缓存不失效! 那 ...
- Swift 字符与字符串
Swift 的 String 和 Character 类型
- U3D4.X版本无法安装MONODEV编辑器
可能是由于机器无法成功安装.NET 4.0的缘故
- Shell之数学计算
本博客已经迁往http://www.kemaswill.com/, 博客园这边也会继续更新, 欢迎关注~ 数学计算是Shell中比较常用的一种操作, 但是因为shell中所有的变量都默认为字符串, ...
- 指定的参数已超出有效值的范围 参数名: utcDate WebResource异常
指定的参数已超出有效值的范围.参数名: utcDate 说明: 执行当前 Web 请求期间,出现未经处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息. 异常详细信息 ...
- Docker练习例子:基于 VNCServer + noVNC 构建 Docker 桌面系统
0. 安装docker 这一步略,网上有好多教程,一般出现装不上的原因,也就是网速问题了,这个我也很难帮你. 1. 下载指定的镜像images docker pull dorowu/ubuntu-de ...
- MyBatis知多少(1)
SQL (Structured Query Language,结构化查询语言)己经存在很长一段时间了.自从第一次提出“数据可以被规范化为一组相互关联的表”这样的思想以来,已经超过35年了. 从那时起, ...
- swift也开源了.
swift也开源了 微软好多也开源. 这世界都开源了 你还等啥. 是因为 B2D 模式吗. 开发者人数众多, 足可以养活一个公司了. 有的叫生态圈.
- Linux高级编程--04.GDB调试程序(设置断点)
调试已运行的程序 在UNIX下用ps查看正在运行的程序的PID(进程ID),然后用gdb PID格式挂接正在运行的程序. 先用gdb 关联上源代码,并进行gdb,在gdb中用attach命令来挂接进程 ...