Lock はトップレベルのインターフェイスであり、そのすべてのメソッドを次の図に示します。
そのサブクラスのリストは次のとおりです:
通常、そのインスタンスを定義するには ReentrantLock を使用します。以下の図:
PS: Sync は同期ロック、FairSync は公正なロック、NonfairSync は不公平なロックを意味します。ReentrantLock の使用どんなスキルの学習も、それを使用することから始まるため、私たちも例外ではありません。まず、ReentrantLock の基本的な使用法を見てみましょう:
public class LockExample { // 创建锁对象 private final ReentrantLock lock = new ReentrantLock(); public void method() { // 加锁操作 lock.lock(); try { // 业务代码...... } finally { // 释放锁 lock.unlock(); } } }
ReentrantLock の作成後、次の 2 つの主要な操作があります。
import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
// 创建锁对象
private static final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
// 定义线程任务
Runnable runnable = new Runnable() {
@Override
public void run() {
// 加锁
lock.lock();
try {
// 打印执行线程的名字
System.out.println("线程:" + Thread.currentThread().getName());
} finally {
// 释放锁
lock.unlock();
}
}
};
// 创建多个线程
for (int i = 0; i < 10; i++) {
new Thread(runnable).start();
}
}
}
上記からわかるように、実行結果、ReentrantLock はデフォルトで不公平なロックです。スレッド名は作成された順にインクリメントされるため、公平なロックであれば、スレッドの実行も順番にインクリメントされるはずですが、上記の結果からわかるように、実行とこの説明 ReentrantLock は、デフォルトでは不当なロックです。
ReentrantLock を公平なロックとして設定するのは非常に簡単です。ReentrantLock を作成するときに true の構築パラメータを設定するだけです。
次のコードが表示されます:import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
// 创建锁对象(公平锁)
private static final ReentrantLock lock = new ReentrantLock(true);
public static void main(String[] args) {
// 定义线程任务
Runnable runnable = new Runnable() {
@Override
public void run() {
// 加锁
lock.lock();
try {
// 打印执行线程的名字
System.out.println("线程:" + Thread.currentThread().getName());
} finally {
// 释放锁
lock.unlock();
}
}
};
// 创建多个线程
for (int i = 0; i < 10; i++) {
new Thread(runnable).start();
}
}
}
上記の結果からわかるように、ReentrantLock に true コンストラクターを明示的に設定すると、パラメータを渡すと、ReentrantLock は公平なロックになり、スレッドがロックを取得する順序が整然となります。
実は、ReentrantLock のソースコードからも、それが公平なロックであるか不公平なロックであるかがわかります。
ReentrantLock のソースコードの一部は次のように実装されています。 ##public ReentrantLock() { sync = new NonfairSync(); } public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
上記のソース コードから、ReentrantLock がデフォルトで不公平なロックを作成することがわかります。作成時に構築パラメーターの値が明示的に true に設定されている場合、公平なロックが作成されます。 2. 最後にロックを解放します
ReentrantLock を使用するときは、忘れずにロックを解放してください。そうしないと、ロックが永久に占有され、ロックを使用している他のスレッドが解放されます。したがって、ReentrantLock を使用する場合は、ロックが確実に解放されるように、最終的にロックを解放する必要があります。反例
import java.util.concurrent.locks.ReentrantLock; public class LockExample { // 创建锁对象 private static final ReentrantLock lock = new ReentrantLock(); public static void main(String[] args) { // 加锁操作 lock.lock(); System.out.println("Hello,ReentrantLock."); // 此处会报异常,导致锁不能正常释放 int number = 1 / 0; // 释放锁 lock.unlock(); System.out.println("锁释放成功!"); } }
上記プログラムの実行結果は次のとおりです。
# # 上記の結果から、例外が発生した場合、ロックが正常に解放されず、ロックを使用している他のスレッドが永続的に待ち状態になることがわかります。
良い例
import java.util.concurrent.locks.ReentrantLock; public class LockExample { // 创建锁对象 private static final ReentrantLock lock = new ReentrantLock(); public static void main(String[] args) { // 加锁操作 lock.lock(); try { System.out.println("Hello,ReentrantLock."); // 此处会报异常 int number = 1 / 0; } finally { // 释放锁 lock.unlock(); System.out.println("锁释放成功!"); } } }上記のプログラムの実行結果は次のとおりです。
From 上記の結果から、メソッド内で例外が発生しても、ReentrantLock ロックの解放操作には影響せず、このロックを使用している他のスレッドは正常に取得して実行できることがわかります。
3. ロックは複数回解除できませんロック操作の回数とロック解除操作の回数は 1 対 1 に対応する必要があり、ロックを複数回解除することはできません。プログラムにエラーを報告させます。
反例 1 つのロックが 2 つのロック解除操作に対応するため、プログラムはエラーを報告して実行を終了します。サンプル コードは次のとおりです:import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
// 创建锁对象
private static final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
// 加锁操作
lock.lock();
// 第一次释放锁
try {
System.out.println("执行业务 1~");
// 业务代码 1......
} finally {
// 释放锁
lock.unlock();
System.out.println("锁释锁");
}
// 第二次释放锁
try {
System.out.println("执行业务 2~");
// 业务代码 2......
} finally {
// 释放锁
lock.unlock();
System.out.println("锁释锁");
}
// 最后的打印操作
System.out.println("程序执行完成.");
}
}
# 上記の結果からわかるように、 2 回目のロック解除が実行されると、プログラムはエラーを報告して実行を終了し、例外後のコードが正常に実行されなくなります。
在使用 ReentrantLock 时,需要注意不要将加锁操作放在 try 代码中,这样会导致未加锁成功就执行了释放锁的操作,从而导致程序执行异常。
反例
import java.util.concurrent.locks.ReentrantLock; public class LockExample { // 创建锁对象 private static final ReentrantLock lock = new ReentrantLock(); public static void main(String[] args) { try { // 此处异常 int num = 1 / 0; // 加锁操作 lock.lock(); } finally { // 释放锁 lock.unlock(); System.out.println("锁释锁"); } System.out.println("程序执行完成."); } }
以上程序的执行结果如下:
从上述结果可以看出,如果将加锁操作放在 try 代码中,可能会导致两个问题:
未加锁成功就执行了释放锁的操作,从而导致了新的异常;
释放锁的异常会覆盖程序原有的异常,从而增加了排查问题的难度。
以上がJava における ReentrantLock の一般的な落とし穴は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。