ロック
(ロックなしで)チケットを販売する簡単な例を見てみましょう。
package demo1;
public class SaleTicketTest {
public static void main(String[] args) {
// lambda 表达式 ()表示run() 其中"()"中可以写明参数 ,->{} 表示 run后的代码块{}
// 支持 lambda 表达式,必须是接口上有 @FunctionalInterface 注解
// @FunctionalInterface 注解的接口,只能存在一个 抽象方法!
Ticket ticket = new Ticket();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"C").start();
}
}
class Ticket{
private Integer num = 40;
public void sale(){
if(num > 0){
num --;
System.out.println(Thread.currentThread().getName()+"卖票,剩余:"+num+"张");
}
}
}
さらに数回実行すると、取得されるログ情報は次のようになります。
注文が乱雑です!
JDK8の新機能:機能インターフェース@FunctionalInterfaceの使用方法
JDK 1.5之前的做法:
テイク
synchronized
ロックします!
class Ticket{
private Integer num = 40;
public synchronized void sale(){
if(num > 0){
num --;
System.out.println(Thread.currentThread().getName()+"卖票,剩余:"+num+"张");
}
}
}
JDK 1.5 之后的做法:
java.util.concurrent.locks.Lock
クラスを使用して実装加锁
および释放锁
操作できます。
package demo1;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SaleTicketTest3 {
public static void main(String[] args) {
// lambda 表达式 ()表示run() 其中"()"中可以写明参数 ,->{} 表示 run后的代码块{}
// 支持 lambda 表达式,必须是接口上有 @FunctionalInterface 注解
// @FunctionalInterface 注解的接口,只能存在一个 抽象方法!
Ticket3 ticket3 = new Ticket3();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket3.sale();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket3.sale();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket3.sale();
}
},"C").start();
}
}
class Ticket3{
private Integer num = 40;//目标数
private Integer saleNum = 0; //卖出数
// 可重入锁(最实用)
// 调用无参构造,生成 “不公平锁”
// 可以传递参数 ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();} true为公平锁
// 不公平锁,性能更好,可以插队!
Lock lock = new ReentrantLock();
public void sale(){
lock.lock(); //加锁
//lock.tryLock();
try {
if(num > 0){
num --;
saleNum ++;
System.out.println(Thread.currentThread().getName()+"卖票,共卖了"+saleNum+"张,剩余:"+num+"张");
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();//释放锁
}
}
}
同期とロックの違い
- Synchronizedはjavaキーワードであり、Lockはjavaの単なるクラスです。
- Synchronizedはロックの状態を認識できませんが、Lockはロックが正常に取得されたかどうかを判断できます。
- 同期されたロックと解放は自動的に行われますが、ロックは手動で行う必要があります。
- 同期されたスレッドがブロックされている場合、他のスレッドは待機を続けますが、ロックは待機しない場合があります(lock.tryLock())。
- 同期は、再入可能ロック、中断
不能、不公平にすることができます。ロックは再入可能ロックにすることができ、中断するかどうかを判断でき、公平ロック/不公平ロックを選択できます。 - 同期は、少量のコード同期の問題に適しています。ロックは、多数の同期コードに適しています。