同時実行性:同じオブジェクトが複数のスレッドによって同時に操作されます。たとえば
、電車のチケットをつかんで同時にお金を引き出します。
スレッドの同期:複数のスレッドが同じリソースを操作します
◆同じプロセスの複数のスレッドが同じストレージ領域を共有するため、同時に便利です、アクセスの競合の問題も発生します。メソッドでアクセスしたときにデータの正確性を保証するために、同期中にロックメカニズムが追加されます。スレッドがオブジェクトの排他ロック、排他リソースを取得すると、他のスレッドは
使用後に待機する必要があります次の問題があります:
◆ロックを保持している1つのスレッドは、このロックを必要とする他のすべてのスレッドをハングさせます。
◆マルチスレッドの競合下では、ロックをロックして解放すると、コンテキストの切り替えとスケジューリングの遅延が増加します、
パフォーマンスの問題の
原因; ◆高優先度のスレッドが低優先度のスレッドがロックを解放するのを待つと、優先度が逆転
し、パフォーマンスの問題が発生します。
同期コードブロック:同期(Obj)()
Objはそれを同期
モニターと呼んでいますObjは任意のオブジェクトですが
、同期モニターとして共有リソースを使用することをお勧めします。同期メソッドは同期モニターであるため、同期メソッドで同期モニターを指定する必要はありません。これはオブジェクト自体、またはクラスです[リフレクションで説明]
◆同期モニターの実行プロセス
1.最初のスレッドがアクセスして同期モニターをロックし、コードを実行します
2. 2番目のスレッドが同期にアクセスして見つけますモニターはロックされており、アクセスできません。3。
最初のスレッドがアクセスした後、同期モニターのロックを解除し
ます。4。2番目のスレッドがアクセスし、同期モニターがロックされていないことを検出し、ロックしてアクセスします。
マルチスレッドでは、3つの安全でない状況があります。
複数の人が駅で同時にチケットを購入する問題、
2人が同時に銀行でお金を引き出す問題、
安全でない回収、
ロック(同期)によって問題を解決できます。
◆駅でチケットを購入
package com.lu.syn;
//不安全的买票,把buy方法加了synchronized就安全了
public class UnsafeBuyTicket {
public static void main(String[] args) {
BuyTicket station = new BuyTicket();
new Thread(station,"我").start();
new Thread(station,"你们").start();
new Thread(station,"黄牛党").start();
}
}
class BuyTicket implements Runnable{
//票
private int ticketNums = 10;
Boolean flag = true;//外部停止方式
@Override
public void run() {
//买票
while(flag){
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//synchronized 同步方法 锁的是this
private synchronized void buy() throws InterruptedException {
//判断是否有票
if(ticketNums <= 0){
flag = false;
return;
}
//模拟延时
Thread.sleep(100);
//买票
System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
}
}
◆銀行引き落とし
package com.lu.syn;
//不安全的2人取钱,使用同步块解决,
//同步块可以锁任何对象
public class UnsafeBank {
public static void main(String[] args) {
//账户
Account account = new Account(500, "结婚基金");
Drawing you = new Drawing(account,50,"you");
Drawing girlFriend = new Drawing(account, 100,"girlFriend");
you.start();
girlFriend.start();
}
}
//账户
class Account{
int money; //余额
String name; //卡名
public Account(int money, String name){
this.money = money;
this.name = name;
}
}
//银行:模拟取款
class Drawing extends Thread{
Account account; //账号
int drawingMoney; //取了多少钱
int nowMoney; // 现在有多少钱
public Drawing(Account account, int drawingMoney, String name){
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
//取钱
//synchronized默认锁的是this
@Override
public void run() {
//锁的对象是变化的量,需要增删改的对象
synchronized (account){
//判断钱够不够
if(account.money - drawingMoney < 0){
System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//卡内余额 = 余额 - 取的钱数
account.money = account.money - drawingMoney;
//手里的钱
nowMoney = nowMoney + drawingMoney;
System.out.println(account.name+"余额为:"+account.money);
//Thread.currentThread().getName() = this.getName()
System.out.println(this.getName() + "手里的钱" +nowMoney);
}
}
}
◆安全でない収集
package com.lu.syn;
import java.util.ArrayList;
import java.util.List;
//线程不安全的集合。添加synchronized同步块就线程安全了
public class UnsafeList {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
synchronized (list){
list.add(Thread.currentThread().getName());
}
}).start();
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
DeadlockMultiple
スレッドはそれぞれいくつかの共有リソースを占有し、他のスレッドが占有するリソースが実行されるのを待機します。
その結果、2つ以上のスレッドがお互いにリソースを解放するのを待機し、すべてが実行を停止します。特定の同期ブロックは
同時に「3つ以上のオブジェクトをロック」すると、「デッドロック」問題が発生する場合があります。
デッドロックに必要な4つの条件:
1.相互に排他的な条件:リソースは、一度に1つのプロセスでのみ使用できます。
2.リクエストとホールドの条件:プロセスがリソースのリクエストによりブロックされた場合、取得したリソースを保持します。
3.非剥奪条件:プロセスによってすでに獲得されたリソースは、使い尽くされる前に強制的に剥奪することはできません。
4.循環待機条件:いくつかのプロセス間で一種の循環待機リソースの関係が形成されます。
1つ以上の条件を破壊する方法を見つける限り、デッドロックを回避できます
ロックロック
JDK5.0以降、Javaはより強力なスレッド同期メカニズムを提供します。
同期は、同期ロックオブジェクトを明示的に定義することによって実現されます。同期ロックは、ロックオブジェクトを使用して
java.util.concurrent.locks.Lockインターフェースとして機能し、複数のスレッドを制御します。共有リソースにアクセスするためのツール
であるReentrantLockクラスは、同期化と同じ同時実行性とメモリセマンティクスを持つLockを実装します。スレッドセーフ
制御の実現では、ReentrantLockがより一般的に使用され、ロックを表示したり、ロックを解除したりできます。
ルックロック形式:
class A{
private final ReentrantLock lock = new Reen TrantLock();
public void m(){
lock.lock();
try{
//保证线程安全的代码;
}
finally{
lock.unlock();
//如果同步代码有异常,要将unlock()写 入finally语句块
}
}
}
同期とロック
ロックの比較は明示的なロックです(手動でロックを開いたり閉じたり、ロックを閉じることを忘れないでください)同期は暗黙的なロックで、
スコープ外で自動的に解放されます
ロックにはコードブロックロックのみがあり、同期にはコードブロックロックとメソッドロックがあります
◆ロックロックを使用すると、JVMはスレッドのスケジュールに費やす時間が短縮され、パフォーマンスが向上します。そして、より優れたスケーラビリティーを備えています(より多くのサブカテゴリーを提供します)
◆優先使用順序:
◆ロック>同期コードブロック(メソッド本体に入り、対応するリソースを割り当てました)>同期メソッド(メソッド本体の外側)
コード演習:
import java.util.concurrent.locks.ReentrantLock;
//测试Lock锁
public class TestLock {
public static void main(String[] args) {
TestLock2 testLock2 = new TestLock2();
//创建并启动3个线程
new Thread(testLock2).start();
new Thread(testLock2).start();
new Thread(testLock2).start();
}
}
class TestLock2 implements Runnable{
int ticketNums = 10;
//定义lock锁,要不然:多个线程同时操作同一个资源,不安全
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
lock.lock();//加锁
if (ticketNums>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ticketNums--);
}else {
break;
}
}finally {
lock.unlock();//解锁
}
}
}
}