一文搞懂java中方法锁、对象锁、类锁、静态锁

synchronized关键字,我们一般称之为“同步锁”,用它来修饰需要同步的方法和需要同步代码块,默认是当前对象作为锁的对象。在用类修饰synchronized时(或者修饰静态方法),默认是当前类的Class对象作为锁的对象,故存在着方法锁、对象锁、类锁这样的概念。

先给出以下代码感受下代码执行的时候为什么需要同步?代码可能比较枯燥,配上业务理解起来就会舒服很多,学生军训,有三列,每列5人,需要报数,每个线程负责每一列报数。

class SynchronizedExample {
	protected static int num = 0;
	protected void numberOff() {
		for(int i=0; i<5; i++) {
			num++;
			System.out.println(Thread.currentThread().getName()+":"+SynchronizedExample.num);
		}
	}
}

public class SynchronizedTest {
	public static void main(String[] args) throws InterruptedException {
		SynchronizedExample se = new SynchronizedExample();
		for(int i=1; i<=3; i++) {
			new Thread( ()->  {se.numberOff();}, "线程"+i).start();
		}
	}
}

执行结果如下:
在这里插入图片描述
之所以出现这种情况,是因为三个线程是异步的,没有同步。对应的业务场景就是,在第一列没有完成报数的时候,其他队列抢报了,这在现实中是不允许的,所以需要类似于synchronized等具有同步功能的关键字粉末登场。
当将报数方法加上synchronized关键字之后,就会一列一列的报数。

	protected synchronized void numberOff() {
		for(int i=0; i<5; i++) {
			num++;
			System.out.println(Thread.currentThread().getName()+":"+SynchronizedExample.num);
		}
	}

加锁后代码执行如下:
在这里插入图片描述
写到这里还是要从技术层面讲下原理,当一个线程执行带有synchronized关键字的方法时,该线程会在该方法处设置一个锁(其他线程打不开这个锁,只能在外边等该线程释放掉该锁,一般都都是执行玩所有代码逻辑主动释放锁),表示此方法是当前线程独占的,对应到上述业务中就是一次只能有一个队列报数。

一、对象锁

改进后的代码用到了一个对象锁,该对象锁默认是当前对象,上述代码等同于以下代码:

	protected void numberOff() {
		synchronized (this) {
			for (int i = 0; i < 5; i++) {
				num++;
				System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
			}
		}
}
当多个线程用一个对象锁,各个线程可以达到同步的作用,如果每个线程都用自己的对象锁,那么synchronized就失去了同步的作用。如以下代码:
class SynchronizedExample {
	protected static int num = 0;

	protected void numberOff() {
		synchronized (this) {
			for (int i = 0; i < 5; i++) {
				num++;
				System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
			}
		}
	}
}

public class SynchronizedTest {

	public static void main(String[] args) throws InterruptedException {
		SynchronizedExample se = new SynchronizedExample();
		for(int i=1; i<=3; i++) {
			new Thread( ()->  {new SynchronizedExample().numberOff();}, "队列"+i).start();
		}
	}
}

在这里插入图片描述
有读者会说不同线程执行的是不同对象中的方法,肯定达不到同步的效果,也对,也很有道理,接着看如下代码:

class SynchronizedExample {
	protected static int num = 0;

	protected void numberOff(Object lock) {
		synchronized (lock) {
			for (int i = 0; i < 5; i++) {
				num++;
				System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
			}
		}
	}
}

public class SynchronizedTest {
	public static void main(String[] args) throws InterruptedException {
		SynchronizedExample se = new SynchronizedExample();
		for(int i=1; i<=3; i++) {
			new Thread( ()->  {se.numberOff(new Object());}, "队列"+i).start();
		}
	}
}

在这里插入图片描述

二、类锁

对于上述问题,读者应该得出一个结论,要想达到同步的效果,必须用同一个锁,此时类锁可以粉末登场。看如下代码:

	protected void numberOff(Object lock) {
		synchronized (SynchronizedExample.class) {
			for (int i = 0; i < 5; i++) {
				num++;
				System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
			}
		}
	}

上述代码可以达到同步的效果。

三、静态锁

静态锁是针对静态方法而言,当一个静态方法中有synchronized关键字时,默认的是使用当前类字节码对象作为锁。代码示例如下:

class SynchronizedExample {
	protected static int num = 0;

	protected synchronized static void numberOff() {
		for (int i = 0; i < 5; i++) {
			num++;
			System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
		}
	}
}

public class SynchronizedTest {
	public static void main(String[] args) throws InterruptedException {
		for (int i = 1; i <= 3; i++) {
			new Thread(() -> { new SynchronizedExample().numberOff(); }, "队列" + i).start();
		}
	}
}

最后炫个技,用线程池将上述代码写一下:

package ioo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class SynchronizedExample {
	protected static int num = 0;
	protected synchronized static void numberOff() {
		for (int i = 0; i < 5; i++) {
			num++;
			System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
		}
	}
}

public class SynchronizedTest {
	public static void main(String[] args) throws InterruptedException {
		ExecutorService executorService = Executors.newCachedThreadPool();
		for(int i=1; i<=3; i++) {
			executorService.execute(() -> new SynchronizedExample().numberOff());
		}
	}
}
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Python面向对象编程(Object-Oriented Programming,简称OOP)是一种程序设计方法,它将数据和操作数据的方法组合成对象,通过定义类(class)来创建对象。下面是一些概念和原则,可以帮助你更好地理解Python面向对象编程。 1. 类和对象: - 类是一种抽象的数据类型,它定义了对象的属性和方法。 - 对象是类的实例,它具有类定义的属性和方法。 2. 属性和方法: - 属性是对象的数据,可以是整数、字符串、列表等。 - 方法对象的行为,可以是函数或过程。 3. 封装: - 封装是将数据和对数据的操作封装在一起,以创建一个独立的实体。 - 使用类来封装数据和方法,可以隐藏实现细节,提高代码的可读性和可维护性。 4. 继承: - 继承是一种机制,允许一个类继承另一个类的属性和方法。 - 子类可以重用父类的代码,并且可以添加新的属性和方法。 5. 多态: - 多态是指同一个方法可以在不同的类具有不同的实现方式。 - 多态可以提高代码的灵活性和可扩展性。 下面是一个简单的例子,展示了如何定义一个类、创建对象并调用对象方法: ```python class Person: def __init__(self, name, age): self.name = name self.age = age def say_hello(self): print(f"Hello, my name is {self.name} and I'm {self.age} years old.") # 创建对象 person = Person("Alice", 25) # 调用对象方法 person.say_hello() ``` 这个例子定义了一个名为`Person`的类,它有两个属性(`name`和`age`)和一个方法(`say_hello`)。我们通过`Person`类创建了一个名为`person`的对象,并调用了它的`say_hello`方法。 希望这个简单的例子能帮助你更好地理解Python面向对象编程。如果你有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东心十

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值