好久没有更新博客了,今天试着用简单的语言把synchronized的使用说清楚。

synchronized是什么?

synchronized是用来保证在多线程环境下代码同步执行的可重入的互斥锁。所谓互斥锁是指锁一旦被某个线程拿到之后,其他线程就无法获取锁,只能等到持有锁的线程的释放之后重新尝试获取。至于可重入,则是指已经获取到锁的那个线程在访问加锁代码块的时候是不需要重新获取锁的,可以直接执行代码块,在稍后的例子中也会有这样的测试代码来验证这一点。

synchronized怎么用?

synchronized有两种使用方式:

1、作用于方法声明处;

public synchronized void test() {
// code here...
}

2、作用于代码块。

public void test() {
// 1. 锁只针对当前对象
synchronized(this) {
// code here...
}
// 2. 针对某一个对象加锁
synchronized(obj) {
// code here...
}
// 3. 针对某一个类加锁
synchronized(XXX.class) {
// code here...
}
}

如果方法内部的代码全部在synchronized(this){}中的话,作用是与第一种方式等价的,内部实现是否一样,这个就不得而知了。

对没有声明锁的方法,或者代码块,不会受到锁的限制的。

死锁

所谓死锁用最简单的话描述就是,两个线程互相持有对方的需要的锁形成的一种僵持状态。比如线程A持有锁Y,等线程B释放锁X,而线程B持有锁X,等线程A释放锁Y。可以通过jstack检测死锁相关问题。避免死锁的发生,需要线程按照顺序获取需要的锁,避免形成竞争。说来简单,coding的时候还要主动注意才行。

synchronized 和 ReentrantLock

两者都是可重入的互斥锁,在语义上可以认为是一样的。区别就是synchronized自动获取锁,执行完毕后自动释放锁,为代码编码带来了较大的便利,同时因为这种便利,也失去灵活性。我们无法控制尝试加锁、主动解锁的场景,ReentrantLock则提供了这种方法的使用,而ReentrantLock的就需要自己来释放锁了,锁一定要放在finally代码块里释放,否则。。。哼哼

测试代码

public class TestSynchronized {

    public static void main(String[] args) throws InterruptedException {
byte[] lock = new byte[0];
final MyRunnable runnable1 = new MyRunnable();
final MyRunnable runnable2 = new MyRunnable();
Thread thread1 = new Thread(runnable1);
thread1.start();
Thread thread2 = new Thread(runnable2);
thread2.start(); // 保证上面的线程先start
Thread.sleep(100L); new Thread(new Runnable() {
@Override
public void run() {
runnable1.testCall();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
runnable2.testCall();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
runnable1.testCall2();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
runnable2.testCall2();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
runnable1.testCall3();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
runnable2.testCall3();
}
}).start(); Thread thread3 = new Thread(new MyLockRunnable(lock));
thread3.start(); Thread thread4 = new Thread(new MyLockRunnable(lock));
thread4.start(); Thread thread7 = new Thread(new MysynchronizedClassRunnable());
thread7.start(); Thread thread8 = new Thread(new MysynchronizedClassRunnable());
thread8.start(); } public static class MyRunnable implements Runnable {
// 防止测试可重入的时候陷入无限递归
boolean testIn = false;
@Override
public void run() {
// 锁只针对当前对象
synchronized (this) {
System.out.println(this.getClass().getName());
// 可重入测试
if (!testIn) {
testIn = true;
this.run();
}
while (true) {}
}
} // 因为run方法一直持有当然对象,所以这个方法永远获取不到锁。
public void testCall() {
synchronized (this) {
System.out.println(Thread.currentThread().getName() + " testCall...");
}
}
// 等价于上面的testCall方法,锁定代码块,只不过这个是锁定的方法级别的代码块
public synchronized void testCall2() {
System.out.println(Thread.currentThread().getName() + " testCall2...");
} // 非锁定方法,可以正常调用
public void testCall3() {
System.out.println(Thread.currentThread().getName() + " testCall3...");
}
} public static class MyLockRunnable implements Runnable {
private final byte[] lock;
MyLockRunnable(byte[] lock) {
this.lock = lock;
} @Override
public void run() {
// 针对所有引用这个lock对象的方法
synchronized (lock) {
System.out.println(this.getClass().getName());
while (true) {}
}
}
} public static class MysynchronizedClassRunnable implements Runnable {
@Override
public void run() {
// 针对这个这个class加锁
synchronized (this.getClass()) {
System.out.println(this.getClass().getName());
while (true) {}
}
}
}
}

synchronized使用说明的更多相关文章

  1. [转]Java 对象锁-synchronized()与线程的状态与生命周期

      线程的状态与生命周期 Java 对象锁-synchronized() ? 1 2 3 4 synchronized(someObject){   //对象锁 } 对象锁的使用说明: 1.对象锁的返 ...

  2. java线程同步以及对象锁和类锁解析(多线程synchronized关键字)

    一.关于线程安全 1.是什么决定的线程安全问题? 线程安全问题基本是由全局变量及静态变量引起的. 若每个线程中对全局变量.静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的:若有多个线 ...

  3. Atitit.项目修改补丁打包工具 使用说明

    Atitit.项目修改补丁打包工具 使用说明 1.1. 打包工具已经在群里面.打包工具.bat1 1.2. 使用方法:放在项目主目录下,执行即可1 1.3. 打包工具的原理以及要打包的项目列表1 1. ...

  4. awk使用说明

    原文地址:http://www.cnblogs.com/verrion/p/awk_usage.html Awk使用说明 运维必须掌握的三剑客工具:grep(文件内容过滤器),sed(数据流处理器), ...

  5. java 多线程 Synchronized方法和方法块 synchronized(this)和synchronized(object)的理解

    synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法:通过在方法声明中加入 synchronized ...

  6. 单例模式中用volatile和synchronized来满足双重检查锁机制

    背景:我们在实现单例模式的时候往往会忽略掉多线程的情况,就是写的代码在单线程的情况下是没问题的,但是一碰到多个线程的时候,由于代码没写好,就会引发很多问题,而且这些问题都是很隐蔽和很难排查的. 例子1 ...

  7. Thread 学习记录 <1> -- volatile和synchronized

    恐怕比较一下volatile和synchronized的不同是最容易解释清楚的.volatile是变量修饰符,而synchronized则作用于一段代码或方法:看如下三句get代码: int i1;  ...

  8. 【Java并发系列04】线程锁synchronized和Lock和volatile和Condition

    img { border: solid 1px } 一.前言 多线程怎么防止竞争资源,即防止对同一资源进行并发操作,那就是使用加锁机制.这是Java并发编程中必须要理解的一个知识点.其实使用起来还是比 ...

  9. (转)Lock和synchronized比较详解

    今天看了并发实践这本书的ReentantLock这章,感觉对ReentantLock还是不够熟悉,有许多疑问,所有在网上找了很多文章看了一下,总体说的不够详细,重点和焦点问题没有谈到,但这篇文章相当不 ...

随机推荐

  1. AngularJS(1)

    AngularJS(1) 在讲正题之前,先说一下有关angular简介方面的信息: 1. angularJS  诞生于2009年,由Misko Hevery 等人创建,后为Google所收购.是一款优 ...

  2. Spring 框架的架包分析、功能作用、优点,及jar架包简介

    Spring 框架的架包详解    Spring的作用     Spring的优势  由于刚搭建完一个MVC框架,决定分享一下我搭建过程中学习到的一些东西.我觉得不管你是个初级程序员还是高级程序员抑或 ...

  3. Eclipse CDT: Shortcut to switch between .h and .cpp

    ctrl+ tab  is the default shortcut.You can change it in Window → Preferences → General → Keys: Toggl ...

  4. Linux的一些基本概述以及系统使用

    GNU:项目名称(意指开发在类UNIX系统上的软件).POSIX:可移植(Portable)操作系统接口,便于程序在不同操作系统上运行. Linux是符合POSIX标准的操作系统: 完全兼容POSIX ...

  5. HTML 学习笔记 (canvas 基础)

    1.什么是Canvas canvas就是一个画布,可以进行画任何的线,图形,填充等一系列操作.这一切都是用Js操作的,另外Canvas不仅仅提供简单的二维矢量绘图,也提供了三维的绘图,以及图片处理等一 ...

  6. 理解SVG的viewport,viewBox,preserveAspectRatio

    万丈高楼平地起,基础很重要. viewport 表示SVG可见区域的大小,或者可以想象成舞台大小,画布大小. <svg width="500" height="30 ...

  7. codevs 1052 地鼠游戏

    1052 地鼠游戏 http://codevs.cn/problem/1052/ 题目描述 Description 王钢是一名学习成绩优异的学生,在平时的学习中,他总能利用一切时间认真高效地学习,他不 ...

  8. linux系统top命令查看系统状态

    Linux系统可以通过top命令查看系统的CPU.内存.运行时间.交换分区.执行的线程等信息.通过top命令可以有效的发现系统的缺陷出在哪里.是内存不够.CPU处理能力不够.IO读写过高. 使用SSH ...

  9. 【原】Learning Spark (Python版) 学习笔记(四)----Spark Sreaming与MLlib机器学习

    本来这篇是准备5.15更的,但是上周一直在忙签证和工作的事,没时间就推迟了,现在终于有时间来写写Learning Spark最后一部分内容了. 第10-11 章主要讲的是Spark Streaming ...

  10. Ubuntu14.04无法在var/www内新建文档

    /var/www文件夹的所有者属于www-data用户组. 要想用你自己的帐号在/var/www里面创建文件和文件夹,最好的办法是把自己的帐号纳入到www-data用户组中. 命令:sudo user ...