1. 程式人生 > >Java多執行緒之執行緒安全與同步例項

Java多執行緒之執行緒安全與同步例項

1.1    執行緒安全與同步例項

1.1.1  購票同步物件鎖

/*

 * 用程式模擬鐵路售票系統:實現通過兩個售票點發售某日某次列車的50張車票,

 * 一個售票點用一個執行緒表示

 */

publicclass SyncDemo {

         public static void main(String[] args) {

                   /*

                    * new SaleTicketThread("視窗1").start(); new

                    * SaleTicketThread("視窗2").start();

                    */

                   // 建立票物件(內部封裝了賣票的方法,並且具備執行線上程中的能力)

                   Ticket tickt = new Ticket();

                   // 讓多個視窗同時賣票(讓執行緒執行指定的任務物件)

                   new Thread(tickt, "視窗1").start();

                   new Thread(tickt, "視窗2").start();

         }

}

classTicket implements Runnable {

         int num = 50;// 票數

         Object obj = new Object();

         @Override

         public void run() {

                   // 不停地賣票

                   while (true) {

                            sale();

                   }

         }

         /**

          * 賣票,每呼叫一次,賣一張票

          */

         //同步方法,其實就是同步程式碼塊的簡寫方式

         public synchronized void sale() {

                   // 同步程式碼塊,同一時間只能有一個執行緒進行執行裡面的程式碼

//               synchronized (this) {// 同步鎖,每個物件都可以作為同步鎖進行使用(可用任何物件)

                            if (num > 0) {

                                     try {

                                               Thread.sleep(100);

                                               System.out.println(Thread.currentThread().getName()

                                                                 +"...sale..." + num--);

                                     } catch(InterruptedException e) {

                                               //TODO Auto-generated catch block

                                               e.printStackTrace();

                                     }

                            }

//               }

         }

}

classSaleTicketThread extends Thread {

         private int num = 50;

         public SaleTicketThread(String name) {

                   super(name);

         }

         @Override

         public void run() {

                   while (num > 0) {

                            System.out.println(getName()+ "......sale....." + num);

                            num--;

                   }

         }

}

1.1.2  同賬戶同步存錢

publicclass Ex1 {

         public static void main(String[] args){

                   Account account = newAccount();

                   new Thread(account, "小強").start();

                   new Thread(account, "小花").start();

         }

}

classAccount implements Runnable{

         private int money = 0;  //存款

         @Override

         public void run() {

                   //存錢三次,每次存100元,並且在讀完之後顯示賬戶的餘額

                   for(int i=0;i<3;i++){

                            saveMoney(100);

                   }

         }

         /**

          * 存錢

          */

         public synchronized void saveMoney(intmoney){

                   this.money +=money;

                   System.out.println(Thread.currentThread().getName()+"存入100元,賬戶餘額為"+this.money);

                   try {

                            Thread.sleep(500);

                   } catch (InterruptedExceptione) {

                            // TODOAuto-generated catch block

                            e.printStackTrace();

                   }

         }       

}

1.1.3  火車過山洞

/*

 * 有5輛火車要過山洞,但確保山洞同時只能有一輛火車通過(過山洞需要1秒),列印輸出火車通過的順序。

 * (過山洞的順序是不可控的,只要保證同一時間只有一輛火車能通過山洞即可)

 * 提示:使用執行緒同步,一輛火車就是一個執行緒

 */

publicclass Ex2 {

         public static void main(String[] args){

                   new Train("火車1").start();

                   new Train("火車2").start();

                   new Train("火車3").start();

                   new Train("火車4").start();

                   new Train("火車5").start();

         }

}

classTrain extends Thread{

         public Train(String name){

                   super(name);

         }

         @Override

         public void run() {

                   synchronized (Train.class) {

                            System.out.println(getName()+"過山洞.....");

                            try {

                                     Thread.sleep(1000);

                            } catch(InterruptedException e) {

                                     // TODOAuto-generated catch block

                                     e.printStackTrace();

                            }

                   }

         }

}

1.1.4  處理單例模式中的執行緒同步問題

在懶漢式單例模式中存線上程同步問題

處理方案:採用雙重判斷的形式同時解決效率和執行緒安全的問題

publicclass Demo {

         public static void main(String[] args){

                   new Thread() {

                            @Override

                            public void run() {

                                     System.out.println(Singleton3.getInstance());

                            }

                   }.start();

                   new Thread() {

                            @Override

                            public void run() {

                                     System.out.println(Singleton3.getInstance());

                            }

                   }.start();

         }

}

// 單例模式(餓漢式)

classSingleton {

         //靜態欄位是在類載入的時候就初始化了

         private static Singleton instance = newSingleton();

         // 私有化構造方法,防止外界建立物件

         private Singleton() {

         }

         public static Singleton getInstance() {

                   return instance;

         }

}

// 單例模式(懶漢式)

// 存線上程安全問題,可以通過雙重判斷加同步處理解決這裡的執行緒安全問題

classSingleton2 {

         private static Singleton2 instance;

         private Singleton2() {

                   // emty

         }

         // 在這裡,執行緒安全問題只會出現在第一次建立物件的時候,只要物件已經被建立完,

         // 那麼就不需要再對程式碼進行同步處理

         // public static synchronizedSingleton2 getInstance(){//存線上程安全問題,可以通過雙重判斷加同步處理解決這裡的執行緒安全問題

         public static Singleton2 getInstance(){

                   if (instance == null) {        //通過雙重判斷物件是否存在

                            synchronized(Singleton2.class) {//同步

                                     if(instance == null) {

                                               try{

                                                        Thread.sleep(100);

                                               }catch (InterruptedException e) {

                                                        //TODO Auto-generated catch block

                                                        e.printStackTrace();

                                               }

                                               instance= new Singleton2();

                                     }

                            }

                   }

                   return instance;

         }

}

/*使用靜態內部類實現單例模式

 * 在類載入的時候會載入類中的成員,會初始化靜態欄位,將類中的成員載入到記憶體中(方法區)

 *

 */

classSingleton3{

         private Singleton3(){

         }

         //靜態程式碼塊只會在類載入的時候被呼叫一次

         static{

                   System.out.println("外部類中的靜態程式碼塊......");

         }

         //靜態內部類

         private static class Inner{

                   static Singleton3 instance =new Singleton3();

                   static{

                            System.out.println("內部類中的靜態程式碼塊.....");

                   }

         }

         public static Singleton3 getInstance(){

                   return Inner.instance;

         }

}

1.1.5  數字和字母的間隔輸出

/**

 * 1.         寫兩個執行緒,一個執行緒列印 1~52,另一個執行緒列印字母A-Z列印順序為12A34B56C……5152Z(2個數字1個字母)。

       提示:使用執行緒間的通訊。

 */

publicclass Ex1 {

         public static void main(String[] args){

                   // TODO Auto-generated methodstub

                   Printer printer = newPrinter();

                   newNumberThread(printer).start();

                   newLetterThread(printer).start();

         }

}

//數字輸出執行緒

classNumberThread extends Thread{

         private Printer printer;

         public NumberThread(Printer printer){

                   this.printer = printer;

         }

         @Override

         public void run() {

                   for(int i=1;i<=52;i++){

                            printer.printNum(i);

                   }

         }

}

//字母輸出執行緒

classLetterThread extends Thread{

         private Printer printer;

         public LetterThread(Printer printer){

                   this.printer = printer;

         }

         @Override

         public void run() {

                   for(charc='A';c<='Z';c++){

                            printer.printLetter(c);

                   }

         }

}

/**

 * 列印輸出類

 */

classPrinter{

         private boolean numOut = false;  //訊號量,記錄數字是否已經輸出

         //輸出數字

         public synchronized void printNum(intnum){

                   try {

                            if(numOut){//如果數字已經輸出,就等待輸出字母

                                     wait();//注意:wait、notify的呼叫者必須是當前同步程式碼塊對應的同步鎖

                            }

                            System.out.println(num);  //輸出數字

                            //如果剛剛輸出的數字是偶數的話,就喚醒字母輸出執行緒

                            if(num % 2 == 0){

                                     numOut =true;  //標記已經輸出數字

                                     notify();       //喚醒字母輸出執行緒去輸出字母

                            }

                            Thread.sleep(200);

                   } catch (InterruptedExceptione) {

                            // TODOAuto-generated catch block

                            e.printStackTrace();

                   }

         }

         //輸出字母

         public synchronized voidprintLetter(char c){

                   try {

                            if(!numOut){    //如果還沒有輸出數字,就等待數字輸出

                                     wait();

                            }

                            System.out.println(c);   //輸出字母

                            numOut = false;       //標記已經輸出國字母,等待輸出數字

                            notify();             //喚醒數字輸出執行緒去輸出數字

                            Thread.sleep(200);

                   } catch (InterruptedExceptione) {

                            // TODOAuto-generated catch block

                            e.printStackTrace();

                   }

         }

}

1.1.6  主子執行緒的迴圈輸出

/**

 * 子執行緒迴圈3次,接著主執行緒迴圈6次,接著又回到子執行緒迴圈3次,接著再回到主執行緒又迴圈6次,如此迴圈10次,請寫出程式

 */

publicclass Ex2 {

         static boolean flag = false; // 記錄子執行緒是否已經輸出

         static Object lock = new Object();

         public static void main(String[] args){

                   // TODO Auto-generated methodstub

                   // 子執行緒

                   new Thread() {

                            @Override

                            public void run() {

                                     try {

                                               for(int i = 1; i <= 10; i++) {

                                                        synchronized(lock) {

                                                                 if(flag) {

                                                                           lock.wait();

                                                                 }

                                                                 System.out.println("~~~~~~~~~~~~~~第" + i

                                                                                    +"回合~~~~~~~~");

                                                                 for(int j = 1; j <= 3; j++) {

                                                                           System.out.println("子執行緒" + j);

                                                                           Thread.sleep(200);

                                                                 }

                                                                 flag= true;

                                                                 lock.notify();

                                                        }

                                               }

                                     } catch(InterruptedException e) {

                                               //TODO Auto-generated catch block

                                               e.printStackTrace();

                                     }

                            };

                   }.start();

                   // 主執行緒

                   for (int i = 1; i <= 10;i++) {

                            try {

                                     synchronized(lock) {

                                               if(!flag){

                                                        lock.wait();

                                               }

                                               for(int j = 1; j <= 6; j++) {

                                                        System.out.println("主執行緒....." + j);

                                                        Thread.sleep(200);

                                               }

                                               flag= false;

                                               lock.notify();

                                     }

                            } catch(InterruptedException e) {

                                     // TODOAuto-generated catch block

                                     e.printStackTrace();

                            }

                   }

         }

}

相關推薦

Java執行執行安全同步例項

1.1    執行緒安全與同步例項 1.1.1  購票同步物件鎖 【 /*  * 用程式模擬鐵路售票系統:實現通過兩個售票點發售某日某次列車的50張車票,  * 一個售票點用一個執行緒表示  */ publicclass SyncDemo {          publi

java線程線程安全

發生 stack 經典 eat int create 加鎖 情況 zed 線程安全和非線程安全是多線程的經典問題,非線程安全會在多個線程對同一個對象並發訪問時發生。 註意1: 非線程安全的問題存在於實例變量中,如果是方法內部的私有變量,則不存在非線程安全問題。 實例變量是對

Java基礎執行執行安全-同步鎖三種形式

首先,我們通過一個案例,演示執行緒的安全問題: 電影院要賣票,我們模擬電影院的賣票過程。假設要播放的電影是 “葫蘆娃大戰奧特曼”,本次電影的座位共100個(本場電影只能賣100張票)。我們來模擬電影院的售票視窗,實現多個視窗同時賣 “終結者”這場電影票(多個視窗一起賣這100張票)需要視窗

[JDK] Java 執行 執行安全

Java 多執行緒 之 執行緒安全 多執行緒併發操作時資料共享如何安全進行? 執行緒安全與共享 多執行緒操作靜態變數(非執行緒安全) SynchronizedLockTest: /** * <p> * 測試類 * </p>

Java執行 執行安全容器的非阻塞容器

                在併發程式設計中,會經常遇到使用容器。但是如果一個容器不是執行緒安全的,那麼他在多執行緒的插入或者

Java執行執行安全非同步執行

多執行緒併發修改一個數據結構,很容易破壞這個資料結構,如散列表。鎖能夠保護共享資料結構,但選擇執行緒安全的實現更好更容易,如阻塞佇列就是執行緒安全的集合。 執行緒安全的集合 Vector和HashTable類提供了執行緒安全的動態陣列和散列表,而ArrayList和H

Java執行執行安全(0)Java記憶體區域Java記憶體模型

概況 本文內容 1.Java記憶體區域劃分 2.Java記憶體模型JMM 3.硬體記憶體架構與Java記憶體模型 4.Jvm中執行緒實現機制 5.執行緒安全問題的原因 一.理解Java記憶體區域與Java記憶體模型 看

java執行 執行協作

也是網上看的一道題目:關於假如有Thread1、Thread2、Thread3、Thread4四條執行緒分別統計C、D、E、F四個盤的大小,所有執行緒都統計完畢交給Thread5執行緒去做彙總,應當如何實現? 蒐集整理了網上朋友提供的方法,主要有: 1. 多執行緒都是Thread或

執行執行安全關鍵字synchronized

    synchronized關鍵字,是多執行緒程式設計時保證執行緒安全使用非常廣泛的java知識。下面我們學習下synchronized的相關知識: 實現原理     synchronized的實現原理是基於記憶體中的lock原則。記憶體模型中的變

Java基礎學習——執行執行

1.執行緒池介紹     執行緒池是一種執行緒使用模式。執行緒由於具有空閒(eg:等待返回值)和繁忙這種不同狀態,當數量過多時其建立、銷燬、排程等都會帶來開銷。執行緒池維護了多個執行緒,當分配可併發執行的任務時,它負責排程執行緒執行工作,執行完畢後執行緒不關閉而是返回執行緒池,

Java執行執行排程(二)

(一)執行緒優先順序 執行緒優先順序用1~10表示,10表示優先順序最高,預設值是5.每個優先順序對應一個Thread類的公用靜態常量。如 public static final int MIN_PRIORITY = 1; public static final int NO

java執行-執行間的通訊

一個生產者與一個消費者 使用的方法: wait():使執行緒停止並釋放鎖。 notify():叫醒執行緒。 例子 工具類 public class ValueObject { public static String value=""; }

Java筆記-執行執行控制

執行緒控制 我們已經知道了執行緒的排程,接下來我們就可以使用如下方法物件執行緒進行控制。 1.執行緒休眠 public static void sleep(long millis):讓當前執行緒處於暫停狀態,millis引數毫秒值,即暫停時間。 程式

Java筆記-執行執行死鎖問題加簡單舉例

死鎖 導致死鎖的原因 Java中死鎖最簡單的情況是,一個執行緒T1持有鎖L1並且申請獲得鎖L2,而另一個執行緒T2持有鎖L2並且申請獲得鎖L1,因為預設的鎖申請操作都是阻塞的,所以執行緒T1和T2永遠被阻塞了。導致了死鎖。 這是最容易理解也是最簡單的死

讀書筆記:java執行執行同步

閱讀的書籍:《java瘋狂講義》 關鍵詞:執行緒安全問題,同步程式碼塊,同步方法,釋放同步監視器的鎖定,同步鎖,死鎖 執行緒安全問題:當使用多個執行緒來訪問同一個資料時,會導致一些錯誤情況的發生 到底什麼是執行緒安全問題呢,先看一個經典的案例:銀行取錢的問題

從零開始學執行執行安全(一)

public class Employees { 2 //程式設計師的等級 3 private int level; 4 //技能庫 5 public Map<String,String> skills; 6 7 //工資 8 pr

Java執行執行的狀態以及之間的切換(轉)

 博主最近幾天在面試的時候,被面試官問到了Java多執行緒的幾種狀態,無疑博主已經把該忘記的都忘記了,很是尷尬,回到家中在網上找到一篇部落格,博主認真閱讀了此文章,寫的很詳細,現轉載分享給大家: Java中執行緒的狀態分為6種。     1. 初始(N

Java執行執行排程詳解

排程的概念 給定時間結點,時間間隔,任務次數,然後自動執行任務 應用場景舉例 1.日誌清理:每隔三個月,清理公司日誌檔案 2.日誌備份:每個一週,備份公司檔案 3.工資結算:每個月29號,考勤彙報,業務結算,計算工資 排程的實現方式:

Java執行執行模式Immutable模式

Immutable模式 概念:保障資料的安全性,不可變的一種模式。 舉例:java.lang.string 實現了Immutable模式。無需為類中的方法宣告為synchronized,無論被多少個執行緒訪問String物件,物件不可變,不需要考慮執行緒的互斥處

【本人禿頂程式設計師】JAVA執行執行間的通訊方式

←←←←←←←←←←←← 我都禿頂了,還不點關注! 一,介紹 本總結我對於JAVA多執行緒中執行緒之間的通訊方式的理解,主要以程式碼結合文字的方式來討論執行緒間的通訊,故摘抄了書中的一些示例程式碼。 二,執行緒間的通訊方式 ①同步 這裡講的同步是指多個執行緒通過synchro