java synchronized关键字浅析
synchronized这个关键字想必学Java的人都应该知道。
直接上例子:
方法级别实例
public class AtomicInteger {
private int index;
public synchronized int addAndGet() {
try {
Thread.sleep(2000l);
} catch (InterruptedException e) {
e.printStackTrace();
}
return ++ index;
}
public int get() {
return index;
}
}
一个自动增长的类,不解释了。
看测试代码:
final AtomicInteger ai = new AtomicInteger();
new Thread(new Runnable() {
@Override
public void run() {
ai.addAndGet();
System.out.println("thread1 finish sleep");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
ai.addAndGet();
System.out.println("thread2 finish sleep");
}
}).start();
这里例子执行结果是这样的:
过2秒,输出thread1 finish sleep
然后再过2秒,输出thread2 finish sleep。
现在我们把AtomicInteger类里的addAndGet方法前的synchronized关键字去掉。
执行结果是这样的:
过2秒,输出 thread1 finish sleep 然后马上输出 thread2 finish sleep (可能先输出thread2 finish sleep)
分析
java中synchronized就是"加锁"的意思, 一个实例中的方法如果加上了synchronized,那么这个方法如果被调用了,就会自动加上一个锁,如果其他线程想要再次调用这个实例的这个方法,那么需要等待之前的线程执行完成之后才能执行。
因此,之前的实例方法之前有synchronized的执行结果就是过2秒输出一段,再过2秒再次输出。
类级别实例
下面。 我们给AtomicInteger加一个静态同步方法。
public static synchronized void sync() {
System.out.println("now synchronized. wait 4 seconds.");
try {
Thread.sleep(2000l);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
测试代码:
final AtomicInteger ai = new AtomicInteger();
AtomicInteger.sync();
new Thread(new Runnable() {
@Override
public void run() {
ai.addAndGet();
System.out.println("thread1 finish sleep");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
ai.addAndGet();
System.out.println("thread2 finish sleep");
}
}).start();
这个测试结果执行结果是这样的:
先输出 now synchronized. wait 4 seconds.
过4秒(因为静态同步方法需要2秒,addAndGet方法也需要2秒),输出 thread1 finish sleep
再过2秒,输出 thread2 finish sleep
分析
从上述类级别的实例可以看出 -> 静态同步方法作用的范围是类,执行了静态同步方法,静态同步方法执行的时候,这个类中的所有方法(无论是否有synchronized, 无论是否静态)都必须等待这个静态同步方法执行完成之后才能进行。
如果我们把AtomicInteger的addAndGet方法的synchronized关键字去掉,那么执行结果是这样的。
先输出 now synchronized. wait 4 seconds.
过4秒,输出 thread1 finish sleep
然后马上又输出 thread2 finish sleep
再来看个例子:
final AtomicInteger ai1 = new AtomicInteger();
final AtomicInteger ai2 = new AtomicInteger(); AtomicInteger.sync(); new Thread(new Runnable() {
@Override
public void run() {
ai1.addAndGet();
System.out.println("ai1 finish sleep");
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
ai2.addAndGet();
System.out.println("ai2 finish sleep");
}
}).start();
执行结果是这样的。
先输出 now synchronized. wait 4 seconds.
过4秒,输出 ai1 finish sleep
然后马上又输出 ai2 finish sleep
小结: 由于静态同步方法是作用于类级别的,因此实例级别的方法调用都收到影响。所以执行AtomicInteger.sync();的时候ai1,ai2都在等待。 当执行完毕的时候,ai1和ai2由于是不同实例,方法级别的synchronized当然互不影响。
资源级别的实例
资源级别的同步其实跟方法级别的同步是一样的,只不过资源级别的同步的作用更加细节一下,它作用的对象是基于资源的。比如实例中的成员变量。
死锁,可以完美说明资源级别的同步。
public class DeadLock {
private static Object obj1 = new Object();
private static Object obj2 = new Object();
public static void main(String[] args) {
new Thread(new SubThread1()).start();
new Thread(new SubThread2()).start();
}
private static class SubThread1 implements Runnable {
@Override
public void run() {
synchronized (obj1) {
try {
Thread.sleep(1000l);
System.out.println("thread1 synchronized obj1 and wait for obj2.");
synchronized (obj2) {
System.out.println("thread1 synchronized obj2");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private static class SubThread2 implements Runnable {
@Override
public void run() {
synchronized (obj2) {
try {
Thread.sleep(1000l);
System.out.println("thread2 synchronized obj2 and wait for obj1.");
synchronized (obj1) {
System.out.println("thread2 synchronized obj1");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
从死锁这个实例可以看出。
子线程1同步obj1资源的时候,其他线程是不能获得obj1这个资源的。同理,子线程同步obj2资源的时候,其他线程是不能获得obj2这个资源的。
因此,子线程1在同步obj1之后,会等待obj2的释放(obj2已经被子线程2同步了,子线程1不能获得);而子线程2在同步obj2之后,会等待obj1的释放(obj1已经被子线程1同步了,子线程2不能获得)。
所以,这个程序将永远地等待下去。 这也就是著名的死锁问题。
我们可以通过jdk提供的一些命令查看是否死锁。
首先通过jps查看当前jdk启动的进程。

找到死锁这个程序的进程号6552之后再通过 jstack -l 6552 查看堆栈信息。

看到jstack发现了一个死锁。
总结
synchronized关键字可以作用在多个场景之下,我们需要区分清楚各个场景的区别,以便我们设计出符合高并发的程序。
之前对java并发这块了解的太少了.. 面试的时候也问到这些问题,发现自己根本答不上来。
java synchronized关键字浅析的更多相关文章
- Java Synchronized 关键字
本文内容 Synchronized 关键字 示例 Synchronized 方法 内部锁(Intrinsic Locks)和 Synchronization 参考资料 下载 Demo Synchron ...
- Java synchronized 关键字详解
Java synchronized 关键字详解 前置技能点 进程和线程的概念 线程创建方式 线程的状态状态转换 线程安全的概念 synchronized 关键字的几种用法 修饰非静态成员方法 sync ...
- Java synchronized关键字用法(清晰易懂)
本篇随笔主要介绍 java 中 synchronized 关键字常用法,主要有以下四个方面: 1.实例方法同步 2.静态方法同步 3.实例方法中同步块 4.静态方法中同步块 我觉得在学习synchro ...
- java synchronized关键字浅探
synchronized 是 java 多线程编程中用于使线程之间的操作串行化的关键字.这种措施类似于数据库中使用排他锁实现并发控制,但是有所不同的是,数据库中是对数据对象加锁,而 java 则是对将 ...
- java synchronized关键字
引用其他人的一段话 Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchro ...
- Java synchronized关键字的理解
转载自:http://blog.csdn.net/xiao__gui/article/details/8188833 在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环 ...
- [java] java synchronized 关键字详解
Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一 ...
- Java:synchronized关键字引出的多种锁
前言 Java 中的 synchronized关键字可以在多线程环境下用来作为线程安全的同步锁.本文不讨论 synchronized 的具体使用,而是研究下synchronized底层的锁机制,以及这 ...
- java synchronized关键字的底层实现
每个对象都有一个锁(Monitor,监视器锁),class对象也有锁,如果synchronized关键字修饰同步代码块,通过反编译可以看到,其实是有个monitorenter和monitorexit指 ...
随机推荐
- 【mysql】排序方法
查询各科成绩前三名的记录,不考虑并列的情况: select a.course_id as 课程ID, a.score as 成绩, count(a.course_id) as 排名 from scor ...
- 4011: [HNOI2015]落忆枫音
4011: [HNOI2015]落忆枫音 链接 分析: 原来是一个DAG,考虑如何构造树形图,显然可以给每个点找一个父节点,所以树形图的个数就是$\prod\limits_u deg[u]$. 那么加 ...
- Openstack入门篇(十七)之Cinder服务-->安装并配置一个本地存储节点
怎样为块存储服务安装并配置存储节点.为简单起见,这里配置一个有一个空的本地块存储设备的存储节点.这个向导用的是 /dev/sdb,此处选用linux-node1节点作为存储节点,需要在vmware中添 ...
- BZOJ3196 二逼平衡树 ZKW线段树套vector(滑稽)
我实在是不想再打一遍树状数组套替罪羊树了... 然后在普通平衡树瞎逛的时候找到了以前看过vector题解 于是我想:为啥不把平衡树换成vector呢??? 然后我又去学了一下ZKW线段树 就用ZKW线 ...
- C#课后练手
猜拳(三局两胜)请输入您的手势:石头用户手势:石头 电脑手势:剪刀用户胜:1 电脑胜:0 请输入您的手势:石头用户手势:石头 电脑手势:石头用户胜:1 电脑胜: ...
- 如何创建XHTML表单
首先奉上本菜曾经的作业——一张模仿智联招聘中的注册表单.虽然没有加样式显得很难看,但表单的基本要素已经具备了. 接下来进入正文,开始介绍各表单元素 form标签: 在创建表单时,第一步就是form标签 ...
- django 部署一个简单的博客系统
转:https://www.cnblogs.com/fnng/p/3737964.html 写的目的, 加深影响,熟悉开发流程, 开发都是练出来的. 环境 python3.5 windows 7 1. ...
- Bailian 2808 校门外的树(入门线段树)
题目链接:http://bailian.openjudge.cn/practice/2808?lang=en_US 总时间限制: 1000ms 内存限制: 65536kB 描述 某校大门外长度为L的马 ...
- jmeter控制器(一)
简单控制器: 也就是最简单的控制器,里面没有任何内容的,如下图所示: 当我设置线程为循环10次时,运行简单控制器及下边的注册,设置如下图: 通过查看结果数得知,注册只成功了一次 ,再注册时出现邮箱已存 ...
- [操作系统]makefile
makefile文件保存了编译器和连接器的参数选项,还表述了所有源文件之间的关系(源代码文件需要的特定的包含文件,可执行文件要求包含的目标文件模块及库等). 创建程序(make程序)首先读取makef ...