この記事は、「新人クリエーションセレモニー」イベントに参加し、一緒にゴールドクリエーションの道を歩み始めました。
このセクションの概要
このセクションでは、主にロックとデッドロックの現象を紹介します。プロセスとスレッドの違い、並行性の問題の理由、および同期されたキーワードを理解する必要がある学生は、この列の最初の2つの記事を読むことができます。
1.ロック
jdk5.0以降、より強力で制御しやすいロック、つまりLockインターフェイスが提供されます。Lockを使用して手動でロックおよびロックを解除できます。これにより、ロックプロセスをより制御しやすくなります。Lockを使用すると、スレッドがロックを正常に取得したかどうかを知ることもできます。また、同期のように小さな部屋でクラスを完全にロックする代わりに、複数のスレッドがクラスの読み取り操作を同時に完了できるようにすることもできます。他のスレッドに操作の実行を許可しない。
まず、同期はJavaのキーワードですが、Lockはインターフェースであることを知っておく必要があります。使用する前に、まずLockオブジェクトを作成する必要があります。最も一般的に使用されるロックインターフェイスの実装クラスはReentrantLockです(再入可能ロック、再入可能ロック、AQS、フェアロックなどの詳細な紹介は次の章で示されます)。この記事ではこれのみを紹介します。
以下のデモを見てください。私はReentrantLockを定義し、最も基本的なロックとロック解除の方法を使用してロックとロック解除を完了しました。
public class LearnThread implements Runnable {
private static int count=0;
private ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
lock.lock();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " 阻塞的 " + (count++));
}
lock.unlock();//你可以尝试在其他时机解锁,比如i==5时,来观察发生的情况。
}
public static void main(String[] args) {
LearnThread t1 = new LearnThread();
new Thread(t1, "线程1").start();
new Thread(t1, "线程2").start();
}
}
复制代码
ここでロックを使用する方法は実際には非標準です。ロックが常に解放されるようにする必要があります。通常、ロックされるコードは、行lock.lock()と一緒にtryコードブロックに含まれ、ロックされることはtryブロックに含まれます。ステートメントlock.unlock()はfinallyセクションに記述されます。
また、tryLockメソッドを使用して、ロックを取得し、成功または失敗に対して別の方法で処理することもできます。
public class LearnThread implements Runnable {
private static int count=0;
private ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
if(lock.tryLock()) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " 阻塞的 " + (count++));
}
lock.unlock();
}
else{
System.out.println(Thread.currentThread().getName() + " 获取锁失败! ");
}
}
public static void main(String[] args) {
LearnThread t1 = new LearnThread();
new Thread(t1, "线程1").start();
new Thread(t1, "线程2").start();
}
}
复制代码
これは私のコンピュータでこのような出力を与えます
线程1 阻塞的 0
线程1 阻塞的 1
线程1 阻塞的 2
线程2 获取锁失败!
线程1 阻塞的 3
线程1 阻塞的 4
复制代码
スレッド2が途中でロックを取得しようとしたが、失敗し、失敗ポリシー(「ロックの取得に失敗しました」という文を出力)を実行してから破棄したことがはっきりとわかります。
2.デッドロック現象
想象一个这样的场景,你和你的哥哥在家里,都想给自己做一杯美味的香蕉奶昔。可是家里只剩下一根香蕉和一杯牛奶了。你率先拿到了香蕉,而你哥哥占有了牛奶。现在你们两僵持不下,彼此都不想让步,情况一直这样持续下去,你们都没法喝到美味的香蕉奶昔。
线程之间也会出现这样的情况,看看下面这个demo
class A{
public static int n=10;
}
class B{
public static int n=5;
}
public class LearnThread implements Runnable {
private final static A a=new A();
private final static B b=new B();
@Override
public void run() {
if(Thread.currentThread().getName().equals("线程1")) {
synchronized (a) {
System.out.println(Thread.currentThread().getName() + " 拿到了a ");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {
System.out.println(Thread.currentThread().getName() + " 拿到了b ");
}
System.out.println(a.n + b.n);
}
}else{
synchronized (b) {
System.out.println(Thread.currentThread().getName() + " 拿到了b ");
synchronized (a) {
System.out.println(Thread.currentThread().getName() + " 拿到了a ");
}
System.out.println(a.n + b.n);
}
}
}
public static void main(String[] args) {
LearnThread t1 = new LearnThread();
new Thread(t1, "线程1").start();
new Thread(t1, "线程2").start();
}
}
复制代码
我们的类t1里只有一个A和一个B,我们首先让线程1拿到了a,再用Threa.sleep函数强制让它等待0.1秒,这个间隙里,线程2拿到了b。现在它们都想拿到对方手上的资源,很可惜,我们没有设置让步策略,它们会这样持续下去,直到你自己中断程序。
输出结果如下:
线程1 拿到了a
线程2 拿到了b
复制代码
死锁的其他知识点将在面经篇中展示,这里只对概念做一个基本介绍。