Java的知识点31——线程同步
線程同步——并發控制
并發:同一個對象多個線程同時操作
線程不安全: 數據有負數、相同
開辟多線程,每個線程都有自己的工作空間? 與 主存 進行交互
/*** 線程不安全: 數據有負數、相同* @author Administrator**/ public class UnsafeTest01 {public static void main(String[] args) {//一份資源UnsafeWeb12306 web=new UnsafeWeb12306();System.out.println(Thread.currentThread().getName());//多個代理new Thread(web,"馬畜").start();new Thread(web,"碼農").start();new Thread(web,"碼蝗").start();} } class UnsafeWeb12306 implements Runnable{//票數private int ticketNums=10;private boolean flag=true;@Overridepublic void run() {while(flag) {test();}}private void test() {if(ticketNums<0) {flag=false;return;}//模擬延時try {Thread.sleep(200);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);} }線程不安全:取錢
/*** 線程不安全:取錢* @author Administrator**/ public class UnsafeTest02 {public static void main(String[] args) {//賬戶Account account=new Account(100, "結婚禮金");Drawing you=new Drawing(account, 80, "可悲的你");Drawing wife=new Drawing(account, 90, "happy的她");you.start();wife.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 packetTotal; //口袋的總數public Drawing(Account account, int drawingMoney,String name) {super(name);this.account = account;this.drawingMoney = drawingMoney;}@Overridepublic void run() {if(account.money-drawingMoney<0) {return;}try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}account.money -= drawingMoney;packetTotal+=drawingMoney;System.out.println(this.getName()+"-->賬戶余額為:"+account.money);System.out.println(this.getName()+"-->口袋的錢為:"+packetTotal);}}線程不安全:操作容器
import java.util.ArrayList; import java.util.List;/*** 線程不安全:操作容器* @author Administrator**/ public class UnsafeTest03 {public static void main(String[] args) {List<String> list=new ArrayList<String>();for(int i=0;i<1000;i++) {new Thread(()->{list.add(Thread.currentThread().getName());}).start();}System.out.println(list.size());} }什么是線程同步
? 同步問題的提出
? ? ? 現實生活中,我們會遇到“同一個資源,多個人都想使用”的問題。 比如:教室里,只有一臺電腦,多個人都想使用。天然的解決辦法就是,在電腦旁邊,大家排隊。前一人使用完后,后一人再使用。
線程同步的概念
? ? ??處理多線程問題時,多個線程訪問同一個對象,并且某些線程還想修改這個對象。 這時候,我們就需要用到“線程同步”。 線程同步其實就是一種等待機制,多個需要同時訪問此對象的線程進入這個對象的等待池形成隊列,等待前面的線程使用完畢后,下一個線程再使用。
由于同一進程的多個線程共享同一塊存儲空間,在帶來方便的同時,也帶來了訪問沖突的問題。為了保證數據在方法中被訪問時的正確性,在訪問時加入鎖機制(synchronized),當一個線程獲得對象的排他鎖,獨占資源,其他線程必須等待,使用后釋放鎖即可。
存在以下問題:1. 一個線程持有鎖會導致其他需要此鎖的線程掛起
? ? ? ? ? ? ? ? ? ? ? ? ?2. 在多線程競爭下,加鎖、釋放鎖會導致比較多的上下文切換和調度延時,引起性能問題
? ? ? ? ? ? ? ? ? ? ? ? ?3. 如果一個優先級高的線程等待一個優先級低的線程釋放會導致優先級倒置,引起性能問題。
由于可以通過 private 關鍵字來保證數據對象只能被方法訪問,所以我們只需針對方法提出一套機制,這套機制就是synchronized關鍵字,它包括兩種用法:synchronized 方法和 synchronized 塊。
? synchronized 方法
? ? ??通過在方法聲明中加入 synchronized關鍵字來聲明,語法如下:
? ? ? ??
?synchronized 方法控制對“對象的類成員變量”的訪問:每個對象對應一把鎖,每個 synchronized 方法都必須獲得調用該方法的對象的鎖方能執行,否則所屬線程阻塞,方法一旦執行,就獨占該鎖,直到從該方法返回時才將鎖釋放,此后被阻塞的線程方能獲得該鎖,重新進入可執行狀態。
??synchronized 方法的缺陷:若將一個大的方法聲明為synchronized 將會大大影響效率。
線程安全: 在并發時保證數據的正確性、效率盡可能高
?* synchronized
?* 1、同步方法
?* 2、同步塊
//目標不對鎖定失敗
同步塊:synchronized(obj){}? obj? 稱為 同步監視器
塊:局部塊 構造塊 靜態塊? 普通塊
同步方法中無需指定同步監視器,因為同步方法的同步監視器是this即對象本身,或class即類的模子
/*** 線程安全: 在并發時保證數據的正確性、效率盡可能高* synchronized* 1、同步方法* 2、同步塊 ,目標更明確* @author Administrator**/ class Account{int money;String name;public Account(int money, String name) {this.money = money;this.name = name;} }public class SynBlockTest01 {public static void main(String[] args) { //賬戶Account account =new Account(100,"結婚禮金");SynDrawing you = new SynDrawing(account,80,"可悲的你");SynDrawing wife = new SynDrawing(account,90,"happy的她");you.start();wife.start();} } //模擬取款 線程安全 class SynDrawing extends Thread{Account account ; //取錢的賬戶int drawingMoney ;//取的錢數int packetTotal ; //口袋的總數 public SynDrawing(Account account, int drawingMoney,String name) {super(name);this.account = account;this.drawingMoney = drawingMoney;}@Overridepublic void run() {test() ;}//目標鎖定accountpublic void test() {//提高性能if(account.money<=0) {return ;}//同步塊synchronized(account) {if(account.money -drawingMoney<0) {return; }try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}account.money -=drawingMoney;packetTotal +=drawingMoney;System.out.println(this.getName()+"-->賬戶余額為:"+account.money);System.out.println(this.getName()+"-->口袋的錢為:"+packetTotal);}} }線程安全:操作容器
import java.util.ArrayList; import java.util.List;/*** 線程安全:操作容器* @author Administrator**/ public class SynBlockTest02 {public static void main(String[] args) throws InterruptedException {List<String> list=new ArrayList<String> ();for(int i=0;i<10000;i++) {new Thread(()-> {//同步塊synchronized (list) {list.add(Thread.currentThread().getName());}}).start();}Thread.sleep(1000);System.out.println(list.size());} }?
總結
以上是生活随笔為你收集整理的Java的知识点31——线程同步的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java的知识点30——线程的优先级、终
- 下一篇: 计算机网络知识点3——数据交换(报文交换