1.同期コードブロック:
チケット
販売ケースはスレッドセーフの問題に対応し、存在しない重複したチケットを販売しました
解決策1:同期コードブロックの
形式を使用する:
synchronized(){
可能会出现线程安全问题的代码(访问了共享数据的代码)
}
注:
1.コードブロックのロックオブジェクトを介して、任意のオブジェクトを使用できます
。2.ただし、複数のスレッドで使用されるロックオブジェクトが同じであることを確認する必要があります。
ロックオブジェクト
は、同期コードブロックをロックするように機能し、同期コードには1つのスレッドしかありません。ブロック実行
【同期技術の原理】
例として、チケット販売の3つのスレッドを取り上げます。
ロックオブジェクトが使用され、このロックオブジェクトは同期ロックと呼ばれ、オブジェクトロックまたはオブジェクトモニターとも呼ばれます。
3个线程一起抢夺CPU的执行权,谁抢到了谁执行run方法,进行卖票
t0抢到了CPU的执行权,执行run方法,遇到synchronized代码块
这时t0会检查synchronized代码块是否有锁对象
发现有,【就会获取到锁对象,进入到同步中执行】
t1抢到了CPU的执行权,执行run方法,遇到synchronized代码块
这时t1会检查synchronized代码块是否有锁对象
【发现没有,t1,就会进入到阻塞状态,会一直等待t0线程归还锁对象,一直到t0线程执行完同步中的代码,会把锁对象归还给同步代码块,t1才能继续获取到锁对象进入到同步中执行】
t2同理。
由此我们可以得出:【同步中的线程,没有执行完毕不会释放锁,同步外的线程没有锁进不去】
** [同期により、1つのスレッドのみが共有データを同期して実行できることが保証され、安全が確保されます] **ただし、プログラムは頻繁にロックを判断し、ロックを取得し、ロックを解放するため、プログラムの効率が低下します。
コードデモ:
public class RunnableImpl implements Runnable{
//定义一个多线程共享的票源
private int ticket = 100;
//创建一个锁对象
Object lock = new Object();
//设置线程任务:卖票
@Override
public void run() {
//使用死循环,让卖票偶重复执行
while (true) {
synchronized (lock) {
//先判断票是否存在
if(ticket > 0) {
//票存在,卖票 ticket--
//提高安全问题出现的概率,让程序睡眠
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//票存在,卖票 tichet--
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖第:" + ticket-- +"张票。");
}
}
}
}
}
2.同期方法
同期メソッド:同期によって変更されたメソッドは、同期メソッドと呼ばれます。これにより、Aスレッドがメソッドを実行するとき、他のスレッドはメソッドの外部でのみ待機できます。
形式:
使用する手順:
1.共有データにアクセスするコードを取り出し、メソッドに配置します
。2. メソッドにsynchronized修飾子を追加します。
格式:定义方法的格式
修饰符 synchronized 发挥值类型 方法名(参数列表) {
可能出现线程安全的代码(访问了共享数据的代码)
}
同期メソッドは、メソッド内のコードもロックし、
1つのスレッドのみが実行できるようにします。
同期メソッドのロックオブジェクトは、クラスオブジェクトnew RunnableImpl()を実装する
ことです。
コードデモ:
public class RunnableImpl implements Runnable{
//定义一个多线程共享的票源
private int ticket = 100;
//设置线程任务:卖票
@Override
public void run() {
while (ticket > 0) {
payTicket();
}
}
/*
定义一个同步方法
同步方法也会把方法内部的代码锁住
只让一个线程执行
同步方法的锁对象是谁,就是实现类对象 new RunnableImpl()
也就是this
*/
public synchronized void payTicket() {
//先判断票是否存在
if(ticket > 0) {
//票存在,卖票 ticket--
//提高安全问题出现的概率,让程序睡眠
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "-->正在,卖第"+ ticket + "张票");
ticket--;
}
}
}
ロック
java.util.concurrent.locks.Lock接口
Lock 实现提供了比synchronized方法和语句可获得的更广泛的锁定操作
Lock接口中的方法:
public void lock() //:加同步锁。
public void unlock() //:释放同步锁。
[使用手順:]
1.メンバーの場所にReentrantLockオブジェクトを作成します
2. Lockインターフェースでメソッドlockを
呼び出して、セキュリティの問題が発生する可能性のあるコードの前にロックを取得します3.セキュリティの問題が発生する可能性のあるコードの後にLockインターフェースでunlockメソッドを呼び出しますロックを解除する
プログラムのデモ
public class RunnableImpl implements Runnable{
//定义一个多线程共享的票源
private int ticket = 100;
// 1.在成员位置创建一个ReentrantLock对象
Lock lock = new ReentrantLock();
//设置线程任务:卖票
@Override
public void run() {
while (true) {
//2.在可能会出现安全问题的代码前调用Lock接口中方法lock获取锁
lock.lock();
//先判断票是否存在
if(ticket > 0) {
//票存在,卖票 ticket--
//提高安全问题出现的概率,让程序睡眠
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "-->正在,卖第"+ ticket + "张票");
ticket--;
}
//3.在可能会出现安全问题的代码后调用Lock接口中方法unlock释放锁
lock.unlock();
}
}
}