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. go 数组、切片

    数组定义      // 标准 ]], , , , } fmt.Println("a", a) // 自动推导类型 b := [], , , , } fmt.Println(&qu ...

  2. UOJ UR#9 App管理器

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

  3. PostgreSQL内存使用增长观察

    磨砺技术珠矶,践行数据之道,追求卓越价值 回到上一级页面:PostgreSQL内部结构与源代码研究索引页    回到顶级页面:PostgreSQL索引页 [作者 高健@博客园  luckyjackga ...

  4. 查内存命令之free

    磨砺技术珠矶,践行数据之道,追求卓越价值 回到上一级页面: PostgreSQL杂记页     回到顶级页面:PostgreSQL索引页 [作者 高健@博客园  luckyjackgao@gmail. ...

  5. 洛谷 P1762 偶数

    洛谷 P1762 偶数 题目描述 给定一个正整数n,请输出杨辉三角形前n行的偶数个数对1000003取模后的结果. 输入输出格式 输入格式: 一个数 输出格式: 结果 输入输出样例 输入样例#1:   ...

  6. [NOI2018]归程 kruskal重构树

    [NOI2018]归程 LG传送门 kruskal重构树模板题. 另一篇文章里有关于kruskal重构树更详细的介绍和更板子的题目. 题意懒得说了,这题的关键在于快速找出从查询的点出发能到达的点(即经 ...

  7. springmvc ajax传递json值时出现400错误 (问题出在sql上)

    问题出在sql的int不能达到 10000000000 这个值,从 int(11) 修改成 varchar(20) 就可以正常存储了

  8. asp.net core 发布到docker 极简步骤

    1.使用dotnet命令发布项目 2.把发布成功的文件通过scp等工具发布到linux服务器上,在当前目录下新建一个dockerfile 3.使用asp.net core镜像为底包构建一个新的镜像 4 ...

  9. selenium+java多层级frame切换的问题

    关于selenium多层iframe切换,及iframe没有id和name属性的情况下进行切换的问题.(如下图:) 问题: 1. 在切入到frame:left中后,直接切换其他同级和上级frame报错 ...

  10. TCP协议的特点

    tcp 面向连接,三次握手,创建会话:双向的关闭tcp 可靠性,具备传输确认机制,接收端会对接收到的数据进行ack确认;tcp 具备 rtt (raund动态估算传输时间;tcp 具备超时重传机制tc ...