并发编程大师系列之: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关键字了,下面看看 ...
随机推荐
- linux下源码安装rabbitMq
一.安装erlang前期环境安装1.利用yum安装erlang编译所依赖的环境 yum -y install make gcc gcc-c++ kernel-devel m4ncurses-devel ...
- 15-16 ICPC europe J Saint John Festival (graham扫描法+旋转卡壳)
题意:给n个大点,m个小点$(n<=1e5,m<=5e5),问有多少个小点,存在3个大点,使小点在三个大点组成的三角形内. 解题思路: 首先,易证,若该小点在某三大点行成的三角形内,则该小 ...
- django使用pyecharts(3)----django加入echarts_定时全量更新
三.Django 前后端分离_定时全量更新图表 1.安装 djangorestframework linux pip3 install djangorestframework windows pip ...
- Redis--zset类型操作命令
有序集合类型 zset (sorted set ) redis 有序集合zset和集合set一样也是string类型元素的集合,且不允许重复的成员. 不同的是 zset 的每个元素都会关联一个分数(分 ...
- python技巧 — Chrome浏览器中的 XPath Helper
用于XPath 爬取网页结构的时候使用, 安装后 快捷键调用 左边 ctrl+ shift+x 启动 安装流程: 1. 打开chrome浏览器,扩展程序 .搜索 XPath Helper 下载安装(前 ...
- WEB学习路线2019完整版(附视频教程+网盘下载地址)
WEB学习路线2019完整版(附视频教程+网盘下载地址).适合初学者的最新WEB前端学习路线汇总! 在当下来说web前端开发工程师可谓是高福利.高薪水的职业了.所以现在学习web前端开发的技术人员也是 ...
- S04_CH03_QSPI烧写LINUX系统
S04_CH03_QSPI烧写LINUX系统 3.1概述 3.2搭建硬件系统 本章硬件工程还是使用<S04_CH01_搭建工程移植LINUX/测试EMMC/VGA>所搭建的VIVADO工程 ...
- Mybatis配置、逆向工程自动生成代码(CRUD案例)
目的: mybatis简介 搭建mybatis环境 基于SSM逆向工程的使用 Mybatis增删改查案例 mybatis简介 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及 ...
- Selenium 调用IEDriverServer打开IE浏览器
Selenium 调用IEDriverServer打开IE浏览器 2016年03月30日 09:49:37 标签: selenium 14836 Selenium 调用IEDriverServer打开 ...
- QT-入门:创建项目时遇到工程工具集(Kit)找不到问题
创建项目遇到了以下提示: Please add a kit in the options or via the maintenance tool of the SDK 解决方法: 在指定的工具链中设置 ...