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