说到并发编程,感觉跟大多数人一样,谈之色变,说它简单把,其实很有内容,说难吧,用起来也挺容易,最近我硬着头皮,决心要把并发编程好好的搞一遍。以前,面试的时候,面试官问,并发编程会吗?嗯,接触过,就加一个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. htm5手机端实现拖动图片

    htm5手机端实现拖动图片 <pre> <!doctype html><html><head> <title>Mobile Cookbook ...

  2. TCP/IP学习笔记9--以太网之基本概念1: 分类,连接方式

    时间是变化的财富.时钟模仿它,却只有变化而无财富. -- 泰戈尔 以太网(Ethernet)一词源于Ether(以太), 是介质的意思.在爱因斯坦哥们提出量子力学之前,人们普遍认为宇宙空间充满以太,并 ...

  3. IDEA 的操作与使用

    idea 设置syso File –> Setting –> Editor –> Live Templates debug 调试: F7 在 Debug 模式下,进入下一步,如果当前 ...

  4. linux服务器安装jdk (手动解压方式安装)

    linux服务器安装jdk 使用的是通过手动解压安装的方式,没有通过yum或者apt-get命令安装 准备: 下载一个jdk,版本自选,后缀为(.tar.gz) 开始 创建目录 mkdir /usr/ ...

  5. 随机数种子random.seed()理解

    总结: 若采用random.random(),每次都按照一定的序列(默认的某一个参数)生成不同的随机数. 若采用随机数种子random.seed(100),它将在所设置的种子100范围内调用rando ...

  6. Windows10下Anaconda+Tensorflow+Keras环境配置

    注意!注意!!注意!!! (重要的事情说三遍) 安装前检查: 1.Tensorflow不支持Anaconda2,Tensorflow也不支持python2.7和python3.7(满满的辛酸泪!) 2 ...

  7. sublime自动格式化方法

    Sublime 工具自带代码格式化的功能,但在某些场景下格式化代码后并不是我们想要的代码格式,且是点击保存ctrl+s才触发的格式代码事件,so,为关闭点击ctrl+s格式代码,我们需要改命令 sav ...

  8. 14 IF函数

    情景 某销售表,如果员工的销售额大于5000元,提成为10%,否则为8% IF函数 =IF(表达式,值1,值2) 判断表达式,如果表达式为真,显示值1,如果表达式为假,显示值2 示例

  9. pandas之时间重采样笔记

    周期由高频率转向低频率称为降采样:例如5分钟股票交易数据转换为日交易数据 相反,周期也可以由低频转向高频称为升采样 其他重采样:例如每周三(W-WED)转换为每周五(W-FRI) import pan ...

  10. 2019牛客多校八 H. How Many Schemes (AC自动机,树链剖分)

    大意: 给定树, 每条边有一个字符集合, 给定$m$个模式串, $q$个询问$(u,v)$, 对于路径$(u,v)$中的所有边, 每条边从对应字符集合中取一个字符, 得到一个串$s$, 求$s$至少包 ...