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. Angular vs. React - the tie breaker

    https://www.airpair.com/angularjs/posts/angular-vs-react-the-tie-breaker

  2. 20155211 课下测试ch11补做

    20155211 课下测试ch11补做 Web服务器的实现基于HTTP协议,有关HTTP协议,下面说法正确的是() A.可以用telnet充当Web服务器的客户端进行调试 B.HTTP请求的GET和P ...

  3. 传统神经网络ANN训练算法总结

    传统神经网络ANN训练算法总结 学习/训练算法分类 神经网络类型的不同,对应了不同类型的训练/学习算法.因而根据神经网络的分类,总结起来,传统神经网络的学习算法也可以主要分为以下三类: 1)前馈型神经 ...

  4. Wannafly挑战赛18C 异或和

    傻逼题,和期望没毛关系... 分开xy坐标,n方直接统计每个坐标的曼蛤顿距离即可.. #include<bits/stdc++.h> #define il inline #define v ...

  5. Struts 2 访问Servlet API的方式

    与Servlet API解耦的访问方式 与Servlet API耦合的访问方式 (tips:耦合既依赖) 1.    与Servlet API解耦的访问方式 2.     与Servlet API耦合 ...

  6. Linux(centos7)之更换安装python3(二)

    Linux不比window好安装python,折腾了好久,终于成功安装上了python,window上一个安装包完事,可惜Linux上python版本太低不好使,还要更换为3版本,百度了好久,教程上总 ...

  7. AndroidStudio下使用 RecyclerView xml文件不显示预览条目并报错类似:NoClassDefFoundError 问题解决

    在项目中使用RecyclerView是很普遍的,最近工作中遇到了这种情况: RecyclerView可以正常使用 不会报错 但是在layout中的xml文件中不显示并且报错,如下图:(报的错忘了截了, ...

  8. CentOS 下 SonarQube 6.7 的下载、配置、问题排查

    CentOS 下 SonarQube 6.7 的下载.配置.问题排查 系统: CentOS 7 x86_64 SonarQube 版本: 6.7.3 Java 版本: 1.8.0_171 MySQL ...

  9. 【转】Linux系统下的ssh使用

    Linux系统下的ssh使用(依据个人经验总结)   对于linux运维工作者而言,使用ssh远程远程服务器是再熟悉不过的了!对于ssh的一些严格设置也关系到服务器的安全维护,今天在此,就本人工作中使 ...

  10. 阿里路由框架ARouter的使用步骤

    ARouter的使用步骤(以宿主APP modulebase和moduleuser 三大模块组成的工程为例) 第一步 因为路由跳转是子模块都需要用到的,所以我们在module_base模块中引入 co ...