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关键字浅析的更多相关文章

  1. Java Synchronized 关键字

    本文内容 Synchronized 关键字 示例 Synchronized 方法 内部锁(Intrinsic Locks)和 Synchronization 参考资料 下载 Demo Synchron ...

  2. Java synchronized 关键字详解

    Java synchronized 关键字详解 前置技能点 进程和线程的概念 线程创建方式 线程的状态状态转换 线程安全的概念 synchronized 关键字的几种用法 修饰非静态成员方法 sync ...

  3. Java synchronized关键字用法(清晰易懂)

    本篇随笔主要介绍 java 中 synchronized 关键字常用法,主要有以下四个方面: 1.实例方法同步 2.静态方法同步 3.实例方法中同步块 4.静态方法中同步块 我觉得在学习synchro ...

  4. java synchronized关键字浅探

    synchronized 是 java 多线程编程中用于使线程之间的操作串行化的关键字.这种措施类似于数据库中使用排他锁实现并发控制,但是有所不同的是,数据库中是对数据对象加锁,而 java 则是对将 ...

  5. java synchronized关键字

    引用其他人的一段话 Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchro ...

  6. Java synchronized关键字的理解

    转载自:http://blog.csdn.net/xiao__gui/article/details/8188833 在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环 ...

  7. [java] java synchronized 关键字详解

    Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一 ...

  8. Java:synchronized关键字引出的多种锁

    前言 Java 中的 synchronized关键字可以在多线程环境下用来作为线程安全的同步锁.本文不讨论 synchronized 的具体使用,而是研究下synchronized底层的锁机制,以及这 ...

  9. java synchronized关键字的底层实现

    每个对象都有一个锁(Monitor,监视器锁),class对象也有锁,如果synchronized关键字修饰同步代码块,通过反编译可以看到,其实是有个monitorenter和monitorexit指 ...

随机推荐

  1. UOJ UR#9 App管理器

    题目传送门 题目大意大概就是给你一个混合图(既有有向边又有无向边),对于每条无向边,u-v,问删去u->v,或删去v->u那条可以使新图强连通.(保证数据有解). 这道题前几个数据点送分. ...

  2. Web层框架对网站中所有异常的统一处理

    一个网站的异常信息作为专业的人士,是不会轻易暴露给用户的,因为那样狠不安全,显得你漏是一回事,只要还是考虑到网站的数据安全问题,下面给大家分享一下一些常见的web层框架是如何处理统一的异常. 之前都是 ...

  3. MySQL ZIP Archive 5.7.17 安装方法

    1.下载 2.解压缩 3.创建/修改配置文件 在MySQL安装目录下,新建my.ini,内容如下参考 [mysql] # 设置mysql客户端默认字符集 default-character-set=u ...

  4. linux设置禁止ping

    linux禁止ping为了服务器的安全, 防止网络攻击(DOS 攻击消耗网络宽带,CPU资源), 需要服务器设置 禁止ping通常有两种方式第一种是通过防火墙 iptables 设置第二种是内核设置 ...

  5. 如何配置pycaffe

    首先,使用cmake配置.生成caffe的vs2015工程时,设定生成python接口,即BUILD项->BUILD_python.BUILD_python_layer,注意使用CMake生成V ...

  6. Spring Boot之拦截器与过滤器(完整版)

    作者:liuxiaopeng 链接:http://www.cnblogs.com/paddix 作者:蓝精灵lx原文:https://blog.csdn.net/liuxiao723846/artic ...

  7. python多线程创建与使用(转)

    原文:http://codingpy.com/article/python-201-a-tutorial-on-threads/ 创建多线程 创建多线程主要有2种方式. 使用threading.Thr ...

  8. 使用C#采集Shibor数据到Excel

    对Shibor的变化一直以来比较关注,正好最近学习了对html数据处理的一些知识,就打算拿来采集一些我需要的Shibor数据. 使用到的库 HttpAgilityPack 一个非常不错的html解析工 ...

  9. Hadoop源码阅读环境搭建(IDEA)

    拿到一份Hadoop源码之后,经常关注的两件事情就是 1.怎么阅读?涉及IDEA和Eclipse工程搭建.IDEA搭建,选择源码,逐步导入即可:Eclipse可以选择后台生成工程,也可以选择IDE导入 ...

  10. ceilometer 源码分析(polling)(O版)

    一.简单介绍ceilometer 这里长话短说, ceilometer是用来采集openstack下面各种资源的在某一时刻的资源值,比如云硬盘的大小等.下面是官网现在的架构图 这里除了ceilomet ...