Android 技能图谱学习路线系列-Java基础之方法锁、对象锁、类锁

先了解一下Synchronized的用法。
一、Synchronized的用法
在修饰代码块的时候需要一个reference对象作为锁的对象。
在修饰方法的时候默认是当前对象作为锁的对象。
在修饰类时候默认是当前类的Class对象作为锁的对象。

二、三种锁得区别与用法
1、方法锁(synchronized修饰方法时)
在定义方法时加入 synchronized关键字来声明 synchronized 方法。
synchronized 方法控制对类成员变量的访问:
每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态,从而有效避免了类成员变量的访问冲突。
看一下代码:

    public class TestSynchronizedMethod {
	private int count = 0;
	
	public static void main(String[] args) {
		TestSynchronizedMethod testSynchronized = new TestSynchronizedMethod();
		
		Thread threadA = new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("threadA开始执行");
				testSynchronized.methodASynchronized();
				System.out.println("threadA结束");
			}
		});
		threadA.start();
		
		Thread threadB = new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("threadB开始执行");
				testSynchronized.methodBSynchronized();
				System.out.println("threadB结束");
			}
		});
		threadB.start();
	}
	
	public synchronized void methodASynchronized(){
		System.out.println("methodASynchronized获得锁");
		for(int i=0;i<5;i++){
			count++;
			System.out.println("methodASynchronized-count="+count);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("methodASynchronized释放锁");
	}
	
	public synchronized void methodBSynchronized(){
		System.out.println("methodBSynchronized获得锁");
		for(int i=0;i<5;i++){
			count++;
			System.out.println("methodBSynchronized-count="+count);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("methodBSynchronized释放锁");
	}

}

输出结果:

    threadA开始执行
    methodASynchronized获得锁
    methodASynchronized-count=1
    threadB开始执行
    methodASynchronized-count=2
    methodASynchronized-count=3
    methodASynchronized-count=4
    methodASynchronized-count=5
    methodASynchronized释放锁
    threadA结束
    methodBSynchronized获得锁
    methodBSynchronized-count=6
    methodBSynchronized-count=7
    methodBSynchronized-count=8
    methodBSynchronized-count=9
    methodBSynchronized-count=10
    methodBSynchronized释放锁
    threadB结束

从输出结果可以看出,加了同步锁的两个方法,在不同的线程中调用后,先执行的方法会先获得锁,全部执行完毕后才释放锁,之后其他方法继续执行。

2、对象锁(synchronized修饰方法或代码块)
当一个对象中有synchronized method或synchronized block的时候调用此对象的同步方法或进入其同步区域时,就必须先获得对象锁。如果此对象的对象锁已被其他调用者占用,则需要等待此锁被释放。(方法锁也是对象锁中的一种)

线程进入synchronized方法或synchronized 块的时候获取该对象的锁(这个锁由JVM自动获取和释放),如果已经有线程获取了这个对象的锁,则当前线程会等待;synchronized方法或synchronized 块正常返回或者抛异常而终止,JVM会自动释放对象锁。
对象锁的两种方式:
(1)方法锁也是对象锁

   public synchronized void methodASynchronized(){
		System.out.println("methodASynchronized 我是方法锁也是对象锁");
	}

(2)对象锁,代码块形式

public void methodBSynchronized(){
		synchronized (this) {
			System.out.println("methodBSynchronized 我是对象锁");
		}
	}

看一下代码:

      public class TestSynchronizedObject {
	private int count = 0;
	
	public static void main(String[] args) {
		TestSynchronizedObject testSynchronized = new TestSynchronizedObject();
		
		Thread threadA = new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("threadA开始执行");
				testSynchronized.methodASynchronized();
				System.out.println("threadA结束");
			}
		});
		threadA.start();
		
		Thread threadB = new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("threadB开始执行");
				testSynchronized.methodBSynchronizedBlock();
				System.out.println("threadB结束");
			}
		});
		threadB.start();
	}
	
	public synchronized void methodASynchronized(){
		System.out.println("methodASynchronized获得锁");
		System.out.println("methodASynchronized 我是方法锁也是对象锁");
		for(int i=0;i<5;i++){
			count++;
			System.out.println("methodASynchronized-count="+count);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("methodASynchronized释放锁");
	}
	
	public void methodBSynchronizedBlock(){
		synchronized (this) {
			System.out.println("methodBSynchronizedBlock获得锁");
			System.out.println("methodBSynchronizedBlock 我是对象锁");
			for(int i=0;i<5;i++){
				count++;
				System.out.println("methodBSynchronizedBlock-count="+count);
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			System.out.println("methodBSynchronizedBlock释放锁");
		}
	}

}

运行结果如下:

threadA开始执行
methodASynchronized获得锁
methodASynchronized 我是方法锁也是对象锁
methodASynchronized-count=1
threadB开始执行
methodASynchronized-count=2
methodASynchronized-count=3
methodASynchronized-count=4
methodASynchronized-count=5
methodASynchronized释放锁
threadA结束
methodBSynchronizedBlock获得锁
methodBSynchronizedBlock 我是对象锁
methodBSynchronizedBlock-count=6
methodBSynchronizedBlock-count=7
methodBSynchronizedBlock-count=8
methodBSynchronizedBlock-count=9
methodBSynchronizedBlock-count=10
methodBSynchronizedBlock释放锁
threadB结束

从输出结果可以看出,在同一个对象中,不论是同步方法还是同步块,在不同的线程中调用后,先执行的方法会先获得锁,全部执行完毕后才释放锁,之后其他方法继续执行。

3、类锁(synchronized 修饰静态的方法或代码块)
一个class不论被实例化多少次,它的静态方法或静态变量在内存中都只有一份。所以,一旦一个静态的方法被申明为synchronized。此类所有的实例化对象在调用此方法时共用同一把锁,称之为类锁。

与对象锁不同的是,对象锁是用来控制实例方法之间的同步,类锁是用来控制静态方法(或静态变量互斥体)之间的同步。

类锁的两种方式:
(1)静态方法

 public static synchronized void methodASynchronizedClass(){
    		System.out.println("methodASynchronizedClass我是静态方法");
    	}

(2)代码块

public void methodBSynchronizedClass(){
		synchronized (TestSynchronizedClass.class) {
			System.out.println("methodASynchronizedClass我是同步代码块");
		}
	}

看一下代码:

public class TestSynchronizedClass {
	private static int count = 0;
	
	public static void main(String[] args) {
		TestSynchronizedClass testSynchronized1 = new TestSynchronizedClass();
		TestSynchronizedClass testSynchronized2 = new TestSynchronizedClass();
		
		Thread threadA = new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("threadA开始执行");
				testSynchronized1.methodASynchronizedClass();
				System.out.println("threadA结束");
			}
		});
		threadA.start();
		
		Thread threadB = new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("threadB开始执行");
				testSynchronized2.methodBSynchronizedClass();
				System.out.println("threadB结束");
			}
		});
		threadB.start();
	}
	
	public static synchronized void methodASynchronizedClass(){
		System.out.println("methodASynchronizedClass获得锁");
		System.out.println("methodASynchronizedClass我是静态方法");
		for(int i=0;i<5;i++){
			count++;
			System.out.println("methodASynchronizedClass-count="+count);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("methodASynchronizedClass释放锁");
	}
	
	public void methodBSynchronizedClass(){
		synchronized (TestSynchronizedClass.class) {
			System.out.println("methodBSynchronizedClass获得锁");
			System.out.println("methodASynchronizedClass我是同步代码块");
			for(int i=0;i<5;i++){
				count++;
				System.out.println("methodBSynchronizedClass-count="+count);
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			System.out.println("methodBSynchronizedClass释放锁");
		}
	}

}

运行结果如下:

threadA开始执行
methodASynchronizedClass获得锁
methodASynchronizedClass我是静态方法
methodASynchronizedClass-count=1
threadB开始执行
methodASynchronizedClass-count=2
methodASynchronizedClass-count=3
methodASynchronizedClass-count=4
methodASynchronizedClass-count=5
methodASynchronizedClass释放锁
threadA结束
methodBSynchronizedClass获得锁
methodASynchronizedClass我是同步代码块
methodBSynchronizedClass-count=6
methodBSynchronizedClass-count=7
methodBSynchronizedClass-count=8
methodBSynchronizedClass-count=9
methodBSynchronizedClass-count=10
methodBSynchronizedClass释放锁
threadB结束

从输出结果可以看出,在同一个class对象的不同实例中,不论是同步方法还是同步块,在不同的线程中调用后,先执行的方法会先获得类锁,全部执行完毕后才释放锁,之后其他方法继续执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值