synchronized对象锁和类锁
一 对象锁和类锁简介
我们可以从synchronized加锁位置区分对象锁和类锁。
1、对象锁
普通同步方法,锁是当前实例对象。比如:
public synchronized void doLongTimeTaskC() {}
2、类锁
静态同步方法,锁是当前类的Class对象。比如:
public synchronized static void doLongTimeTaskA() {}
3、同步代码块上的对象锁或类锁
加在同步代码块上,锁是Synchonized括号里配置的对象,可以是实例对象,也可以是Class对象;
public void doLongTimeTaskD() {
synchronized (this) {
}
}
或
public static void doLongTimeTaskE() {
synchronized (Task.class) {
}
}
对象锁和类锁是两个完全不一样的锁,下面通过实例看看他们的区别。
二 对象锁
对象锁分两种情况说明,分别是在实例方法上加锁或在实例方法的代码块上加锁。
下面讨论多个线程持有多个对象,每一个线程控制自己的对象锁,
线程之间异步执行。简单说就是一个线程一个对象,谁也不影响谁。
Task
package com.lanhuigu.thread.synchronizeddemo;
/**
* 可以从synchronized加锁位置区分对象锁和类锁:
* 1、对象锁
*
* 普通同步方法,锁是当前实例对象。比如:
*
* public synchronized void doLongTimeTaskC() {}
*
* 2、类锁
*
* 静态同步方法,锁是当前类的Class对象。比如:
*
* public synchronized static void doLongTimeTaskA() {}
*
* 3、同步代码块
*
* 加在同步代码块上,锁是Synchonized括号里配置的对象,可以是实例对象,也可以是Class对象;
*
* public void doLongTimeTaskD() {
* synchronized (this) {
* }
* }
*
* 或
*
* public static void doLongTimeTaskE() {
* synchronized (Task.class) {
* }
* }
*/
public class Task {
/**
* 对象锁:普通同步方法,锁为当前实例对象。
*/
public synchronized void doLongTimeTaskA() {
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 void doLongTimeTaskB() {
synchronized (this) {
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");
}
}
}
ThreadA
package com.lanhuigu.thread.synchronizeddemo;
public class ThreadA extends Thread{
private Task mTask;
public ThreadA(Task tk){
mTask = tk;
}
@Override
public void run() {
mTask.doLongTimeTaskA();
}
}
ThreadB
package com.lanhuigu.thread.synchronizeddemo;
public class ThreadB extends Thread{
private Task mTask;
public ThreadB(Task tk){
mTask = tk;
}
@Override
public void run() {
mTask.doLongTimeTaskB();
}
}
RunObjectTest
package com.lanhuigu.thread.synchronizeddemo;
/**
* 对象锁测试
*/
public class RunObjectTest {
public static void main(String[] args) {
Task mTaskA = new Task();
Task mTaskB = new Task();
ThreadA ta1 = new ThreadA(mTaskA);
ThreadA ta2 = new ThreadA(mTaskB);
ThreadB tb1 = new ThreadB(mTaskA);
ThreadB tb2 = new ThreadB(mTaskB);
ta1.setName("A1");
ta2.setName("A2");
tb1.setName("B1");
tb2.setName("B2");
ta1.start();
ta2.start();
tb1.start();
tb2.start();
}
}
运行结果:
从运行结果可以看到A1,begin开始后,并没有接着输出A1,end,而是输出了A2,begin,说明两个线程
用的不是同一个锁,如果用的是同一把锁,A1,begin输出,必然需要等A1,end结束释放锁后,
A2获取锁才会接着输出A2,begin。
所以A1,A2分别用的是自己持有对象的锁,线程自己管自己的锁,互不影响,线程异步执行,而不是排队等待执行。
对于B1和B2也是同理。
总结:
多线程分别持有多个对象,每个线程异步执行对象的同步方法,因为JVM为每个对象创建了锁。
如果想让线程排队执行,让多个线程持有同一个对象,线程就会排队执行。
三 类锁
类锁,有在静态方法上加锁的,也有在静态方法代码块上加锁的。
Task
package com.lanhuigu.thread.synchronizeddemo;
/**
* 可以从synchronized加锁位置区分对象锁和类锁:
* 1、对象锁
*
* 普通同步方法,锁是当前实例对象。比如:
*
* public synchronized void doLongTimeTaskC() {}
*
* 2、类锁
*
* 静态同步方法,锁是当前类的Class对象。比如:
*
* public synchronized static void doLongTimeTaskA() {}
*
* 3、同步代码块
*
* 加在同步代码块上,锁是Synchonized括号里配置的对象,可以是实例对象,也可以是Class对象;
*
* public void doLongTimeTaskD() {
* synchronized (this) {
* }
* }
*
* 或
*
* public static void doLongTimeTaskE() {
* synchronized (Task.class) {
* }
* }
*/
public class Task {
// 静态对象
private static Object object = new Object();
/**
* 对象锁:普通同步方法,锁为当前实例对象。
*/
public synchronized void doLongTimeTaskA() {
System.out.println("name = " + Thread.currentThread().getName() + ", begin");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
}
/**
* 对象锁:同步代码块,锁为代码块里面的实例对象。
*/
public void doLongTimeTaskB() {
synchronized (this) {
System.out.println("name = " + Thread.currentThread().getName() + ", begin");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
}
}
/**
* 类锁:静态同步方法,锁为当前Class对象。
*/
public synchronized static void doLongTimeTaskC() {
System.out.println("name = " + Thread.currentThread().getName() + ", begin");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
}
/**
* 类锁:静态同步方法,锁为当前Class对象。
*/
public synchronized static void doLongTimeTaskD() {
System.out.println("name = " + Thread.currentThread().getName() + ", begin");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
}
/**
* 同步代码块:里面的对象可以是Class对象,也可以是实例对象。
*/
public static void doLongTimeTaskE() {
synchronized (Task.class) {// Class对象
//synchronized (object) {// 实例对象
System.out.println("name = " + Thread.currentThread().getName() + ", begin");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
}
}
}
然后创建3个线程,分别调用TaskA中的3个方法。
ThreadC
package com.lanhuigu.thread.synchronizeddemo;
public class ThreadC extends Thread{
private Task mTask;
public ThreadC(Task tk){
mTask = tk;
}
@Override
public void run() {
mTask.doLongTimeTaskC();
}
}
ThreadD
package com.lanhuigu.thread.synchronizeddemo;
public class ThreadD extends Thread{
private Task mTask;
public ThreadD(Task tk){
mTask = tk;
}
@Override
public void run() {
mTask.doLongTimeTaskD();
}
}
ThreadE
package com.lanhuigu.thread.synchronizeddemo;
public class ThreadE extends Thread{
private Task mTask;
public ThreadE(Task tk){
mTask = tk;
}
@Override
public void run() {
mTask.doLongTimeTaskE();
}
}
RunClassTest
package com.lanhuigu.thread.synchronizeddemo;
/**
* 类锁测试
*/
public class RunClasstTest {
public static void main(String[] args) {
Task mTask = new Task();
ThreadC tc = new ThreadC(mTask);
ThreadD td = new ThreadD(mTask);
ThreadE te = new ThreadE(mTask);
tc.setName("C");// 静态同步方法
td.setName("D");// 静态同步方法
te.setName("E");// 静态方法同步代码块
tc.start();
td.start();
te.start();
}
}
运行结果:
从程序运行结果可以看到,结果按照某个线程begin,然后接着输出end,说明线程按顺序执行同步方法。
因为,三个线程持有的是Task的Class类锁,是同一个锁,所以线程需要排队等待执行,直到获取锁才能执行,
这就是结果按顺序输出的原因,这也是类锁的特性,多个线程持有一个类锁,排队执行,持有就是王者,
否则就排队等待。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法