Java-并发-锁-synchronized之对象锁和类锁
0x01 概述
1.1 更多信息
synchronized是java中最常用的一种锁机制,本篇文章主要介绍他的两种用途:类锁和对象锁。
关于synchronized的更多内容可以查看这篇文章: Java-并发-锁-synchronized
更多关于Java锁的信息,可参考文章:Java-并发-关于锁的一切
1.2 总览
几张图片转自图解Java多线程,作者 任何忧伤,都抵不过世界的美丽
1.2.1 实例方法
1.2.2 静态方法
1.2.3 代码块的同步
用jstack查看,同一个监视器对象只允许有一个线程访问:
1.2.4 实例方法的同步加上代码块this的同步
仍然针对同一个实例对象
1.2.5 自定义监视器对象
0x02 对象锁
synchronized
作为对象锁时,用在非静态方法或非静态对象上,下面是示例:
/**
* 对象锁
*/
public synchronized void nonStaticMethodLock(){
for(int i = 0 ; i< 5 ; i++){
System.out.println(Thread.currentThread().getName()+" nonStaticMethodLock");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 对象锁
*/
public void objectLock(){
synchronized(this){
for(int i = 0 ; i< 5 ; i++){
System.out.println(Thread.currentThread().getName()+" objectLock");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
0x03 类锁
类锁修饰方法、代码块的效果和对象锁是一样的,因为类锁只是一个抽象出来的概念,只是为了区别静态方法的特点。因为静态方法是所有对象实例共用的,所以对应synchronized修饰的静态方法的锁也是唯一的,所以抽象出来个类锁。
下面是代码示例:
/**
* 类锁
*/
public void classLock(){
synchronized(Test3.class){
for(int i = 0 ; i< 5 ; i++){
System.out.println(Thread.currentThread().getName()+" classLock");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 类锁
*/
public static synchronized void staticMethodLock(){
for(int i = 0 ; i< 5 ; i++){
System.out.println(Thread.currentThread().getName()+" staticMethodLock");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
0x04 代码示例
下面是完整的代码示例,可以自行调试观察结果,加深理解:
package demos.concurrent.thread.synchronizedTest.objectAndMethodLock;
/**
* Created by chengc on 2018/10/22.
*/
public class Test3 {
private Object nonStaticLockObj = new Object();
private static Object staticLockObj = new Object();
private static Object staticLockObj2 = new Object();
/**
* 类锁
*/
public void classLock(){
synchronized(Test3.class){
for(int i = 0 ; i< 5 ; i++){
System.out.println(Thread.currentThread().getName()+" classLock");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 类锁
*/
public static synchronized void staticMethodLock(){
for(int i = 0 ; i< 5 ; i++){
System.out.println(Thread.currentThread().getName()+" staticMethodLock");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void ordinaryMethod(){
for(int i = 0 ; i< 5 ; i++){
System.out.println(Thread.currentThread().getName()+" ordinaryMethod");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 对象锁
*/
public synchronized void nonStaticMethodLock(){
for(int i = 0 ; i< 5 ; i++){
System.out.println(Thread.currentThread().getName()+" nonStaticMethodLock");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 对象锁
*/
public void thisObjectLock(){
synchronized(this){
for(int i = 0 ; i< 5 ; i++){
System.out.println(Thread.currentThread().getName()+" thisObjectLock");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 对象锁
*/
public void nonStaticObjectLock(){
synchronized(nonStaticLockObj){
for(int i = 0 ; i< 5 ; i++){
System.out.println(Thread.currentThread().getName()+" nonStaticLockObj");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 对象锁
*/
public void staticObjectLock(){
synchronized(staticLockObj){
for(int i = 0 ; i< 5 ; i++){
System.out.println(Thread.currentThread().getName()+" staticLockObj");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 对象锁
*/
public void staticObjectLock2(){
synchronized(staticLockObj2){
for(int i = 0 ; i< 5 ; i++){
System.out.println(Thread.currentThread().getName()+" staticLockObj2");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
Test3 test1 = new Test3();
new Thread(new Runnable() {
@Override
public void run() {
test1.classLock();
}
},"Thread1").start();
new Thread(new Runnable() {
@Override
public void run() {
test1.nonStaticMethodLock();
}
},"Thread2").start();
new Thread(new Runnable() {
@Override
public void run() {
test1.ordinaryMethod();
}
},"Thread3").start();
new Thread(new Runnable() {
@Override
public void run() {
test1.staticMethodLock();
}
},"Thread4").start();
new Thread(new Runnable() {
@Override
public void run() {
test1.thisObjectLock();
}
},"Thread5").start();
new Thread(new Runnable() {
@Override
public void run() {
test1.nonStaticObjectLock();
}
},"Thread6").start();
new Thread(new Runnable() {
@Override
public void run() {
test1.staticObjectLock();
}
},"Thread7").start();
new Thread(new Runnable() {
@Override
public void run() {
test1.staticObjectLock2();
}
},"Thread8").start();
}
}
0x05 总结
通过以上代码调试,总结如下:
- 写在方法上的synchronized锁和写在代码块上用
this
修饰的对象锁,(同个对象锁)一个进程同时只能有一个线程进入执行,但不影响其他方法执行 - 写在静态方法和代码块上用
XXX.class
修饰的为类锁,一个进程中同时只能有一个线程进入执行,但不影响其他方法执行 - 用其他自己声明的对象(不管是静态还是非静态)作为对象锁修饰的方法或是代码块,互不影响
- 普通方法不受对象锁和类锁影响
关于synchronized的更多内容可以查看这篇文章: Java-并发-锁-synchronized
更多关于Java锁的信息,可参考文章:Java-并发-关于锁的一切