说到并发编程,感觉跟大多数人一样,谈之色变,说它简单把,其实很有内容,说难吧,用起来也挺容易,最近我硬着头皮,决心要把并发编程好好的搞一遍。以前,面试的时候,面试官问,并发编程会吗?嗯,接触过,就加一个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的类锁和对象锁的更多相关文章

  1. 并发编程大师系列之:wait/notify/notifyAll/condition

    1. wait().notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写. 2. 调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的mon ...

  2. 并发编程大师系列之:线程的定义和中断 interrupt

    1.启动线程的三种方式: 1.1继承Thread类 public static class UseThread extends Thread { public void run() { System. ...

  3. 并发编程大师系列之:CountDownLatch和Join

    业务场景描述:假设一条流水线上有三个工作者:worker1,worker2,worker3.有一个任务的完成需要他们三者协作完成,worker3可以开始这个任务的前提是worker1和worker2完 ...

  4. 并发编程学习笔记(3)----synchronized关键字以及单例模式与线程安全问题

    再说synchronized关键字之前,我们首先先小小的了解一个概念-内置锁. 什么是内置锁? 在java中,每个java对象都可以用作synchronized关键字的锁,这些锁就被称为内置锁,每个对 ...

  5. 并发编程之关键字(synchronized、volatile)

    并发编程主要设计两个关键字:一个是synchronized,另一个是volatile.下面主要讲解这两个关键字,并对这两个关机进行比较. synchronized synchronized是通过JMV ...

  6. 并发编程从零开始(十一)-Atomic类

    并发编程从零开始(十一)-Atomic类 7 Atomic类 7.1 AtomicInteger和AtomicLong 如下面代码所示,对于一个整数的加减操作,要保证线程安全,需要加锁,也就是加syn ...

  7. Java并发编程(四)synchronized

    一.synchronized同步方法或者同步块 在了解synchronized关键字的使用方法之前,我们先来看一个概念:互斥锁,顾名思义:能到达到互斥访问目的的锁. 举个简单的例子:如果对临界资源加上 ...

  8. 并发编程(二)concurrent 工具类

    并发编程(二)concurrent 工具类 一.CountDownLatch 经常用于监听某些初始化操作,等初始化执行完毕后,通知主线程继续工作. import java.util.concurren ...

  9. java synchronized类锁,对象锁详解(转载)

    觉得还不错 留个记录,转载自http://zhh9106.iteye.com/blog/2151791 在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看 ...

随机推荐

  1. simple config of webpack

    Demo1操作手册 本Demo演示进行简单配置的基本使用 准备环境 初始化环境, cd到demo目录之后, 执行如下命令: npm init -y npm install webpack webpac ...

  2. feign学习笔记

    使用:

  3. 关于 Visual Studio 的代码度量值

    查看方式:Visual Studio -> Analyze -> Calculate code metrics feature 代码度量(Code Metrics)是用来测量专业标准的软件 ...

  4. 《Mysql - 幻读》

    一:准备 - 为了深入了解幻读,准备数据. CREATE TABLE `t` ( `id` ) NOT NULL, `c` ) DEFAULT NULL, `d` ) DEFAULT NULL, PR ...

  5. Word 固定行间距公式图片显示不全、Word Eculid 字体导致行间距过大、Word 行间距过大

    1. 前言 1.有些文章行间距要求是固定值,比如,固定值15磅,但是这样会导致有些公式.图片显示不全.例如下图: 2.Euclid这个字体很容易导致行间距超大. 2. 解决方案 1.把固定值15磅改为 ...

  6. nfs挂载文件

    1. 安装必备插件  以防centos7默认没有启动nfs服务 yum -y install nfs-utils rpcbind # 启动 rpcbind 和配置开机自启动 systemctl sta ...

  7. babel tsc webpack

    我要用啥?js的话:babel编译+webpack模块打包ts的话:tsc编译成js+babel编译+webpack模块打包浏览器情况:如果您的浏览器支持es6所有语法那么就可以只用webpack来处 ...

  8. 线程一(lock)

    对于线程同步操作最简单的一种方式就是使用 lock 关键字,通过 lock 关键字能保证加锁的线程只有在执行完成后才能执行其他线程.   lock 的语法形式如下. lock(object) {    ...

  9. 解决:error LNK1169: 找到一个或多个多重定义的符号

    每一个c++项目中可以包含多个cpp文件和.h文件,不过只能有而且必须有一个cpp文件中包含main函数,否则就会报错.所以在一个c++项目中不能单独运行一个cpp文件,只能运行一个项目.如果你想一个 ...

  10. Element ui tree 搜索

    搜索框 属性 :filter-node-method="filterNode" 对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点 ...