并发编程大师系列之:Synchronized的类锁和对象锁
说到并发编程,感觉跟大多数人一样,谈之色变,说它简单把,其实很有内容,说难吧,用起来也挺容易,最近我硬着头皮,决心要把并发编程好好的搞一遍。以前,面试的时候,面试官问,并发编程会吗?嗯,接触过,就加一个synchronized关键字就好了,面试官微笑着说,嗯好。特喵的现在感觉来说,这俩low逼。本来写了几行的软文,但感觉在技术文章里面体现,有失风度,明明可以靠文采吃饭,而我却非要靠技术,任性!上代码!
1.对象锁概念:
java的所有对象都含有1个互斥锁,这个锁由JVM自动获取和释放。线程进入synchronized方法的时候获取该对象的锁,当然如果已经有线程获取了这个对象的锁,那么当前线程会等待;synchronized方法正常返回或者抛异常而终止,JVM会自动释放对象锁。这里也体现了用synchronized来加锁的1个好处,方法抛异常的时候,锁仍然可以由JVM来自动释放。
代码格式:
// 对象锁:形式1(方法锁)
public synchronized void Method1() {
System.out.println("我是对象锁也是方法锁");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
} } // 对象锁:形式2(代码块形式)
public void Method2() {
synchronized (this) {
System.out.println("我是对象锁");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
2.类锁的概念:
由于一个class不论被实例化多少次,其中的静态方法和静态变量在内存中都只有一份。所以,一旦一个静态的方法被申明为synchronized。此类所有的实例化对象在调用此方法,共用同一把锁,我们称之为类锁。
代码格式:
public synchronized static void Method3() {
System.out.println("我是类锁");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
} }
3.代码演示类锁和对象锁
下面这段代码是两个类锁和一个对象锁,拿到锁后,睡1秒钟。
// 类锁A
public synchronized static void classLockA() {
System.out.println("name = " + Thread.currentThread().getName() + ", begain");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
} // 类锁B
public synchronized static void classLockB() {
System.out.println("name = " + Thread.currentThread().getName() + ", begain");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
} // 对象锁
public synchronized void objectLock() {
System.out.println("name = " + Thread.currentThread().getName() + ", begain");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end"); }
创建三个线程类:分别调用一个资源中的三个方法
class ThreadA extends Thread {
private Test02 test02;
public ThreadA(Test02 tk) {
test02 = tk;
}
// 调用类锁
public void run() {
test02.classLockA();
}
} class ThreadB extends Thread {
private Test02 test02;
public ThreadB(Test02 tk) {
test02 = tk;
}
// 调用类锁
public void run() {
test02.classLockB();
}
} class ThreadC extends Thread {
private Test02 test02;
public ThreadC(Test02 tk) {
test02 = tk;
}
// 调用对象锁
public void run() {
test02.objectLock();
}
}
main方法:起了三个线程,共同访问一个Test02对象
public static void main(String[] args){ Test02 test02 = new Test02();
ThreadA ta = new ThreadA(test02);
ThreadB tb = new ThreadB(test02);
ThreadC tc = new ThreadC(test02); ta.setName("A");
tb.setName("B");
tc.setName("C"); ta.start();
tb.start();
tc.start();
}
执行的结果:
name = A, begain
name = C, begain
name = A, end
name = B, begain
name = C, end
name = B, end
可以看出由于 classLockA和classLockB都是类锁,即同一个锁,所以 A和B是按顺序执行,即同步的。而C是对象锁,和A/B不是同一种锁,所以C和A、B是 异步执行的。
分析:
对象锁要想保持同步执行,那么锁住的必须是同一个对象,举个例子:
Test02类不变,重起两个线程类:均对对象锁进行了调用
class ThreadA extends Thread {
private Test02 test02;
public ThreadA(Test02 tk) {
test02 = tk;
}
// 调用类锁
public void run() {
test02.objectLock();
}
} class ThreadB extends Thread {
private Test02 test02;
public ThreadB(Test02 tk) {
test02 = tk;
}
// 调用类锁
public void run() {
test02.objectLock();
}
}
main方法:创建两个不同的资源对象,启动两个线程,分别对加锁的方法进行调用
public static void main(String[] args){ Test02 test02 = new Test02();
Test02 test03 = new Test02();
ThreadA ta = new ThreadA(test02);
ThreadB tb = new ThreadB(test03); ta.setName("A");
tb.setName("B"); ta.start();
tb.start();
}
结果如下:
name = A, begain
name = B, begain
name = A, end
name = B, end
可见,是异步执行的,没有达到同步的作用。
改进:只需对类锁进行调用,代码如下:
class ThreadA extends Thread {
private Test02 test02;
public ThreadA(Test02 tk) {
test02 = tk;
}
// 调用类锁
public void run() {
// test02.objectLock();
test02.classLockA();
}
} class ThreadB extends Thread {
private Test02 test02;
public ThreadB(Test02 tk) {
test02 = tk;
}
// 调用类锁
public void run() {
// test02.objectLock();
test02.classLockA();
}
}
main方法:同样是创建了多个对象
public static void main(String[] args){ Test02 test02 = new Test02();
Test02 test03 = new Test02();
ThreadA ta = new ThreadA(test02);
ThreadB tb = new ThreadB(test03); ta.setName("A");
tb.setName("B"); ta.start();
tb.start();
}
结果:
name = A, begain
name = A, end
name = B, begain
name = B, end
达到了同步的效果!
总结:
1. 如果多线程同时访问同一类的 类锁(synchronized 修饰的静态方法)以及对象锁(synchronized 修饰的非静态方法)这两个方法执行是异步的,原因:类锁和对象锁是2中不同的锁。
2. 类锁对该类的所有对象都能起作用,而对象锁不能。
并发编程大师系列之:Synchronized的类锁和对象锁的更多相关文章
- 并发编程大师系列之:wait/notify/notifyAll/condition
1. wait().notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写. 2. 调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的mon ...
- 并发编程大师系列之:线程的定义和中断 interrupt
1.启动线程的三种方式: 1.1继承Thread类 public static class UseThread extends Thread { public void run() { System. ...
- 并发编程大师系列之:CountDownLatch和Join
业务场景描述:假设一条流水线上有三个工作者:worker1,worker2,worker3.有一个任务的完成需要他们三者协作完成,worker3可以开始这个任务的前提是worker1和worker2完 ...
- 并发编程学习笔记(3)----synchronized关键字以及单例模式与线程安全问题
再说synchronized关键字之前,我们首先先小小的了解一个概念-内置锁. 什么是内置锁? 在java中,每个java对象都可以用作synchronized关键字的锁,这些锁就被称为内置锁,每个对 ...
- 并发编程之关键字(synchronized、volatile)
并发编程主要设计两个关键字:一个是synchronized,另一个是volatile.下面主要讲解这两个关键字,并对这两个关机进行比较. synchronized synchronized是通过JMV ...
- 并发编程从零开始(十一)-Atomic类
并发编程从零开始(十一)-Atomic类 7 Atomic类 7.1 AtomicInteger和AtomicLong 如下面代码所示,对于一个整数的加减操作,要保证线程安全,需要加锁,也就是加syn ...
- Java并发编程(四)synchronized
一.synchronized同步方法或者同步块 在了解synchronized关键字的使用方法之前,我们先来看一个概念:互斥锁,顾名思义:能到达到互斥访问目的的锁. 举个简单的例子:如果对临界资源加上 ...
- 并发编程(二)concurrent 工具类
并发编程(二)concurrent 工具类 一.CountDownLatch 经常用于监听某些初始化操作,等初始化执行完毕后,通知主线程继续工作. import java.util.concurren ...
- java synchronized类锁,对象锁详解(转载)
觉得还不错 留个记录,转载自http://zhh9106.iteye.com/blog/2151791 在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看 ...
随机推荐
- ubuntu 安装 svn
sudo apt-get install subversion
- html收尾
<form>input 元素</form> <fieldset ></fieldset > <legend ></legend> ...
- 烽火传递【单调队列优化dp】
题目大意: 1.给出长度为n的数组,要求每m个连续的元素之间必须选一个值作为代价,求该数组的最小代价. 题解思路: 1.显然是线性dp,dp[i]表示选择第 i 个元素时的最小总代价.很明显状态转移方 ...
- [转帖]Docker Hub上镜像发现挖矿蠕虫病毒,已导致2000台主机感染
Docker Hub上镜像发现挖矿蠕虫病毒,已导致2000台主机感染 https://www.kubernetes.org.cn/5951.html 本来想说可以用 official版本的镜像 但是一 ...
- 对比JPA 和Hibernate 和 Mybatis的区别
1.JPA.Hibernate.Mybatis简单了解 1.JPA:本身是一种ORM规范,不是ORM框架.由各大ORM框架提供实现. 2.Hibernate:目前最流行的ORM框架,设计灵巧,文档丰富 ...
- 从零开始学Flask框架-008
数据库 安装Flask-SQLAlchemy扩展库 pip install flask-sqlalchemy 引入SQLAlchemy类 from flask_sqlalchemy import SQ ...
- PAT甲级题分类汇编——图
本文为PAT甲级分类汇编系列文章. 图,就是层序遍历和Dijkstra这一套,#include<queue> 是必须的. 题号 标题 分数 大意 时间 1072 Gas Station 3 ...
- Angular 学习笔记 (Angular 9 & ivy)
refer : https://blog.angularindepth.com/all-you-need-to-know-about-ivy-the-new-angular-engine-9cde47 ...
- wget的url获取方式
获取方式 每次用wget都是在网上查相应的url,但以前没怎么关注过这个url是怎么获取到的,这里总结一下 这里以下载jekins为例: 打开jekins网站:https://jenkins.io/d ...
- SD-定义定价用途的条件表(Condition Table)
https://www.fenginfo.com/815.html 条件表(Condition Table)是SAP条件技术体系中最基础的数据源,它们是一群特定的数据表,表名是以特定字母开头 + 三位 ...