違いは、面接の質問の焦点が何であるかを最終的には、クラスのロックとロックオブジェクト「あなたは、パッケージシリーズを知っています」

私は凧午前、公共番号「古代凧」、技術の技術的な公共の数だけではなく、円は多くの年のプログラムから削除された、主な産業はJavaで、開発者は別のPythonを大幅に削減、また、6をプレイ反応します。春の雲シリーズは完了している、あなたがに行くことができる私のgithubのシリーズのフルコンテンツを視聴します。また、「公共の番号で返信することができますPDFファイルの完全なチュートリアルI精巧なPDF版について」。

ロックとロックは時間から時間に学生がクラスインスタンス上の議論を参照し、クラスでそれを何の違い最後に新しいロックのロックアウトされ、一般的な面接の質問の例ですか?

あなたは完全に理解し、ロックロックの違いや使用のようなオブジェクトように、今日出てきます。学生は急速に維持します。

自由ロックをそこに持っています

絶対的な自由はありませんが、絶対的な自由は、一般の人が気軽にすることができ、道徳、法律、倫理の制約の範囲内でのみ比較的自由、生活の中で障害と混乱に対応しています。

マルチスレッドプログラミングでは、ロックが混乱になります何のロックマルチスレッド環境が存在しない、重大なロックが法的拘束力を持つていること、道徳的である、すべてのスレッドがリソースを競合している、最終的な結果は、一方で、システムのクラッシュを引き起こすことがありますあなたがロックを持っていたら、マルチスレッド環境では、安定的かつ効率的な作業をすることができます。

synchronizedキーワード

我々はヘビー級のロックを呼んで同期、それらのスピンロックなどリエントラントロックReentrantLockのように(AQS)項にヘビー級相対しました。多くの人々は、パフォーマンスの低下は、あまりにも、確信のように見えると言って、同期の単なる言及について話しています。実際、何年も前にあるが、Java 1.7,1.8は、すでにその性能とほとんど隙間なく軽量ロックを最適化するために、同期の多くを行っ。

だから、再び私たちは、プログラムが実際にそれは例えば、網状の多くの場所でそれを使用するがあり、中にいくつかのソースで見ている必要があり、使用されていない場合でも、それを使用することを保証することができます。

以下は、今日のテーマは、カテゴリとロックインスタンス・ロックに入りました。すでに明らか名前で、クラスのロックは、クラスのインスタンスは、クラスのインスタンスでロックされている場所にロックです。

例としては、ロック

类声明后,我们可以 new 出来很多的实例对象。这时候,每个实例在 JVM 中都有自己的引用地址和堆内存空间,这时候,我们就认为这些实例都是独立的个体,很显然,在实例上加的锁和其他的实例就没有关系,互不影响了。

通常我们使用实例锁的方式有下面三种:

1、 锁住实体里的非静态变量

非静态变量是实例自身变量,不会与其他实例共享,所以锁住实体内声明的非静态变量可以实现对象锁。锁住同一个变量的方法块共享同一把锁。

2、锁住 this 对象

this 指的是当前对象实例本身,所以,所有使用 synchronized(this)方式的方法都共享同一把锁。

3、直接锁非静态方法

最简单、最直观的一种方式,直接加在方法返回类型前。

使用对象锁的情况,只有使用同一实例的线程才会受锁的影响,多个实例调用同一方法也不会受影响。

下面来做个测试,开启 5 个线程,每个线程都 new 一个新的实例来分别调用上面三种方式的方法,方法完成的动作就是输出线程名称,然后休眠 10 秒钟。

public class ObjectLock {

private Object lock = new Object();

/**
* 锁住非静态变量
* @throws InterruptedException
*/

public void lockObjectField() throws InterruptedException{
synchronized (lock){
System.out.println(Thread.currentThread().getName());
Thread.sleep(10*1000);
}
}

/**
* 锁住 this 对象 this 就是当前对象实例
* @throws InterruptedException
*/

public void lockThis() throws InterruptedException{
synchronized (this){
System.out.println(Thread.currentThread().getName());
Thread.sleep(10*1000);
}
}

/**
* 直接锁住非静态方法
* @throws InterruptedException
*/

public synchronized void methodLock() throws InterruptedException{
System.out.println(Thread.currentThread().getName());
Thread.sleep(10*1000);
}

public static void main(String[] args){
for (int i = 0; i < 5; i++) {
Thread worker = new Thread(new ObjectLockWorker());
worker.setName("kite-" + i);
worker.start();
}
}

public static class ObjectLockWorker implements Runnable{
@Override
public void run() {
try {
ObjectLock objectLock = new ObjectLock();
// 方式 1
objectLock.lockObjectField();
// 方式 2
//objectLock.lockThis();
// 方式 3
//objectLock.methodLock();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
复制代码
我们预测的结果就是每个线程都会立刻输出线程名称,然后各自休眠 10 秒。

分别调用方式1、2、3,效果都是一样的,我们看到输出结果和我们预测的是一样的,5 个线程都立即输出线程名,然后等待 10 秒,整个程序退出。

类锁

类锁是加载类上的,而类信息是存在 JVM 方法区的,并且整个 JVM 只有一份,方法区又是所有线程共享的,所以类锁是所有线程共享的。

使用类锁的方式有如下方式:

1、锁住类中的静态变量

因为静态变量和类信息一样也是存在方法区的并且整个 JVM 只有一份,所以加在静态变量上可以达到类锁的目的。

2、直接在静态方法上加 synchronized

因为静态方法同样也是存在方法区的并且整个 JVM 只有一份,所以加在静态方法上可以达到类锁的目的。

3、锁住 xxx.class

对当前类的 .class 属性加锁,可以实现类锁。

类锁是所有线程共享的锁,所以同一时刻,只能有一个线程使用加了锁的方法或方法体,不管是不是同一个实例。

下面同样来做个测试,开启 5 个线程,除了调用静态方法的方式,其他两种方式中每个线程都 new 一个新的实例来分别调用,方法内完成的动作就是输出线程名称,然后休眠 10 秒钟。

public class ClassLock {

private static Object lock = new Object();

/**
* 锁住静态变量
* @throws InterruptedException
*/

public void lockStaticObjectField() throws InterruptedException{
synchronized (lock){
System.out.println(Thread.currentThread().getName());
Thread.sleep(10*1000);
}
}

/**
* 锁住静态方法
* @throws InterruptedException
*/

public static synchronized void methodLock() throws InterruptedException{
System.out.println(Thread.currentThread().getName());
Thread.sleep(10*1000);
}

/**
* 锁住 xxx.class
* @throws InterruptedException
*/

public void lockClass() throws InterruptedException{
synchronized (ClassLock.class){
System.out.println(Thread.currentThread().getName());
Thread.sleep(10*1000);
}
}

public static void main(String[] args){
for (int i = 0; i < 5; i++) {
Thread worker = new Thread(new ClassLockWorker());
worker.setName("kite-" + i);
worker.start();
}
}

public static class ClassLockWorker implements Runnable{
@Override
public void run() {
try {
ClassLock classLock = new ClassLock();
// 方式 1
classLock.lockStaticObjectField();
// 方式 2
//ClassLock.methodLock();
// 方式 3
//classLock.lockClass();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
复制代码
我们预测的结果就是刚开始只有1个线程抢到锁,然后输出线程名,之后等待 10 秒中,之后是下一个抢到锁的线程,输出线程名,然后等待 10 秒。直到最后一个抢到锁的线程,整个过程历时大约 50 秒。

分别调用方式1、2、3,观察执行结果,和我们预测的是一致的。

总结

  1. 使用对象锁的情况,只有使用同一实例的线程才会受锁的影响,多个实例调用同一方法也不会受影响。

  2. 类锁是所有线程共享的锁,所以同一时刻,只能有一个线程使用加了锁的方法或方法体,不管是不是同一个实例。

创作不易,小小的赞,大大的暖,快来温暖我。不用客气了,赞我!

我是风筝,公众号「古时的风筝」,一个在程序圈混迹多年,主业 Java,另外 Python、React 也玩儿的很 6 的斜杠开发者。可以在公众号中加我好友,进群里小伙伴交流学习,好多大厂的同学也在群内呦。

おすすめ

転載: juejin.im/post/5e8b4f2be51d4547153d0cd8