前言

synchronized关键字是互斥锁,也称为内部锁

每个对象都有自己的monitor(锁标记),它是为了分配给线程,最多一个线程可以拥有对象的锁

使用

synchronized修饰成员方法,锁的是当前实例对象

下面是一个例子:

class Thread2 implements Runnable{
private int count; //修饰成员方法,锁的是调用它的对象,该例中也即是调用它的线程
public synchronized void run() {
for (int i = 0; i < 5; i ++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++)); Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

调用:

Thread2 t2 = new Thread2();
new Thread(t2).start();
new Thread(t2).start();

synchronized修饰静态方法,锁的是该类的Class对象

下面是一个例子:

class Thread3 implements Runnable {
private static int count; //修饰静态方法, 锁的是这个类的所有对象
public static synchronized void getCounter() {
for (int i = 0; i < 5; i ++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} @Override
public void run() {
getCounter();
}
}

调用:

Thread3 t3_0 = new Thread3();
Thread3 t3_1 = new Thread3();
new Thread(t3_0).start();
new Thread(t3_1).start(); 

synchronized修饰代码块,锁的是()中的配置对象

下面是一个例子:

public class Synchronized {
private int count; public void getCount(){
for (int i = 0; i < 5; i ++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++)); Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) throws Exception {
Thread1 t1 = new Thread1(new Synchronized());
new Thread(t1).start();
new Thread(t1).start();
}
} class Thread1 implements Runnable{
private Synchronized s; public Thread1(Synchronized s) {
this.s = s;
} @Override
public void run() {
//修饰代码块: 锁的是()中配置的对象
synchronized(s) {
s.getCount(); try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

synchronized机制

Jvm需要对两类共享数据进行保护:

1.堆中的实例变量

2.本地方法区类变量

对于对象来说 , 有一个监视器保护实例变量; 对于类来说, 有一个监视器保护类变量

Jvm为每个对象和类关联一个锁,如果某个线程获取了锁, 在它释放锁之前其它的线程时不能获得同样的锁的;

对于一个对象,Jvm会维护一个加锁计数器,线程每获得一次该对象, 计数器+1, 每释放一次, 计数器-1,当计数器=0时,锁就完全释放了

死锁

当线程需要持有多个锁时, 就有可能发生死锁的情况, 比如下面这个情形:

A线程首先获得lock1,在获得lock2;   B线程首先获得lock2,在获得lock1, 
当A线程获得lock1时,B线程获得lock2, 于是A线程等待lock2, B线程等待lock1,
两个线程会无限的等待,这就发生了死锁现象

下面是一个例子:

public class Deadlock {
//监视器对象
private final Object lock1 = new Object();
private final Object lock2 = new Object(); public void instanceMethod1(){
synchronized(lock1){
System.out.println("线程1: 获得lock1,等待lock2");
synchronized(lock2) {
System.out.println("线程1:获得lock2");
}
}
} public void instanceMethod2(){
synchronized(lock2){
System.out.println("线程2: 获得lock2,等待lock1");
synchronized(lock1){
System.out.println("线程2: 获得lock1");
}
}
} public static void main(String[] args){
final Deadlock dld = new Deadlock(); Runnable r1 = new Runnable(){
@Override
public void run(){
while(true){
dld.instanceMethod1();
try{
System.out.println("线程1: 睡眠");
Thread.sleep(1000);
} catch (InterruptedException ie){
}
}
}
}; Runnable r2 = new Runnable(){
@Override
public void run(){
while(true) {
dld.instanceMethod2();
try {
System.out.println("线程2: 睡眠");
Thread.sleep(1000);
}
catch (InterruptedException ie){
}
}
}
}; Thread thdA = new Thread(r1);
Thread thdB = new Thread(r2); thdA.start();
thdB.start();
} }

控制台输出:

线程1: 获得lock1,等待lock2
线程2: 获得lock2,等待lock1

避免发生死锁

生产中,死锁现象一旦发生,很可能会造成灾难性的后果,我们在编码中应该避免死锁现象发生

1、尽量不要编写在同一时刻需要持有多个锁的代码;

2、创建和使用一个大锁来代替若干小锁,并把这个锁用于互斥,而不是用作单个对象的对象级别锁;

锁的优化

synchronize采取独占的方式,它属于悲观锁,它假设了最坏的情况,如果持有锁的线程延迟,其他等待程序就会测试,程序停滞不前

锁自旋

在等待锁时,线程不会立即进入阻塞状态,而是先等一段时间看锁是否被释放

偏向锁

一个线程获得了锁,如果在接下来没有别的线程获得该锁,这个锁会偏向第一个获得它的线程,使一个线程多次获得锁的代价更低

锁膨胀

多次调用粒度太小的锁, 不如一次调用粒度大的锁

轻量级锁

如果存在锁的竞争,除了互斥量的开销外,还会发生CAS操作,在同步期间如果没有锁竞争,使用轻量级锁避免互斥量的开销

Java并发编程--2.synchronized的更多相关文章

  1. Java并发编程:synchronized

    Java并发编程:synchronized 虽然多线程编程极大地提高了效率,但是也会带来一定的隐患.比如说两个线程同时往一个数据库表中插入不重复的数据,就可能会导致数据库中插入了相同的数据.今天我们就 ...

  2. Java并发编程:Synchronized及其实现原理

    Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...

  3. Java并发编程:Synchronized底层优化(偏向锁、轻量级锁)

    Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...

  4. 【转】Java并发编程:synchronized

    一.什么时候会出现线程安全问题? 在单线程中不会出现线程安全问题,而在多线程编程中,有可能会出现同时访问同一个资源的情况,这种资源可以是各种类型的资源:一个变量.一个对象.一个文件.一个数据库表等,而 ...

  5. 4、Java并发编程:synchronized

    Java并发编程:synchronized 虽然多线程编程极大地提高了效率,但是也会带来一定的隐患.比如说两个线程同时往一个数据库表中插入不重复的数据,就可能会导致数据库中插入了相同的数据.今天我们就 ...

  6. 【转】Java并发编程:Synchronized及其实现原理

    一.Synchronized的基本使用 Synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法.Synchronized的作用主要有三个:(1)确保线程互斥的访问同步 ...

  7. 【Java并发编程】synchronized相关面试题总结

    目录 说说自己对于synchronized关键字的了解 synchronized关键字的三种使用 synchronized关键字的底层原理 JDK1.6之后对synchronized关键字进行的优化 ...

  8. Java并发编程实例(synchronized)

    此处用一个小程序来说明一下,逻辑是一个计数器(int i):主要的逻辑功能是,如果同步监视了资源i,则不输出i的值,但如果没有添加关键字synchronized,因为是两个线程并发执行,所以会输出i的 ...

  9. Java并发编程:synchronized、Lock、ReentrantLock以及ReadWriteLock的那些事儿

    目录 前言 synchronized用法 修饰方法 修饰实例方法 修饰静态方法 同步代码块 引出Lock Lock用法 子类:ReentrantLock 读写分离锁:ReadWriteLock Loc ...

  10. Java并发编程:synchronized和锁优化

    1. 使用方法 synchronized 是 java 中最常用的保证线程安全的方式,synchronized 的作用主要有三方面: 确保线程互斥的访问代码块,同一时刻只有一个方法可以进入到临界区 保 ...

随机推荐

  1. hdu2036(多边形面积)

    Description “ 改革春风吹满地, 不会AC没关系; 实在不行回老家, 还有一亩三分地. 谢谢!(乐队奏乐)” 话说部分学生心态极好,每天就知道游戏,这次考试如此简单的题目,也是云里雾里,而 ...

  2. jackson @ResponseBody 处理日期类型的字段

    前言:以前只知道一种方式(@JsonFormat)来处理日期格式问题,今天才发现还有两种方式,并且可以全局设置格式,这里记录一下. 首先,pom.xml 中需要先引入如下 jackson 的依赖: & ...

  3. C#(简单递归)和实现IComparable接口

    递归: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syst ...

  4. 使用catsup快速建立个人博客

    一.安装 time: 2016-01-2 20:30 1.使用pip安装catsup:(sudo) pip install catsup 从旧版本升级到新版本:(sudo) pip install c ...

  5. CentOS7系列--1.3CentOS7用户管理

    CentOS7用户管理 1. 添加用户 [root@centos7 ~]# useradd jack [root@centos7 ~]# passwd jack Changing password f ...

  6. 180328_gVim设置tab为4个空格

    找到gVim安装目录 C:\Program Files (x86)\Vim\ 更改目录下的 _vimrc 文件,这是一个只读文件,需要管理员权限进行修改和保存. 在文件末尾添加下列内容: set ts ...

  7. maven属性、profile、资源过滤、不同环境构建项目

    maven针对不同环境构建项目 maven使用属性.profile及资源过滤支持针对不同环境构建项目 maven属性 maven共有六类属性 1.最常见的是自定义属性,即在pom文件里通过<pr ...

  8. 在Windows2003下如何查看IIS站点中对应的PID值

    分享:查看IIS站点中对应的PID值 在Win2003下,提供了一个命令,可以方便的查看.cmd -> iisapp -a 显示W3WP.exe PID: 1264 AppPoolID: hxW ...

  9. ReadWriteLock ReentrantReadWriteLock

    ReadWriteLock管理一组锁,一个是只读的锁,一个是写锁.读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的. 所有读写锁的实现必须确保写操作对读操作的内存影响.换句话说,一个获得了读锁 ...

  10. OtterTune来了,DBA怎么办

    https://blog.csdn.net/xiangzhihong8/article/details/72887476 最近AI的新闻特别多,席卷了围棋圈之后,成为了技术圈和媒体热捧的话题. 今天又 ...