同步塊對象同步方法能更細粒度的鎖定內容java
同步鎖:太大,容易形成效率低下,過小,鎖不住web
線程安全synchronized 儘量鎖定合理的範圍(不是鎖代碼,而是鎖數據)安全
雙重檢測併發
package com.wxh.syn; //線程安全synchronized 儘量鎖定合理的範圍(不是鎖代碼,而是鎖數據) public class Web12306 implements Runnable { int numberKey = 10; boolean flag = true; public static void main(String[] args) { Web12306 web = new Web12306(); new Thread(web,"馬超").start(); new Thread(web,"關羽").start(); new Thread(web,"曹操").start(); } public void run() { test7(); } //儘量鎖定合理範圍,最合理的方法,雙重檢測 private void test7() { while(flag) { if(numberKey <= 0) { //判斷還有沒有票 flag = false; return; } synchronized(this) { //由於對象爲flag 和numberkey,鎖住一個對象是不安全的, if(numberKey <= 0) { //判斷臨界值,如當只有最後一張票時 flag = false; return; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->"+numberKey--); } } } private void test5() { while(flag) { synchronized(this) { // a,b,c 三個線程,a拿到鎖,進行判斷,釋放鎖,B拿到鎖,釋放鎖,a此時在sleep,B也進入sleep, //但sleep結束,cpu調度可能先執行B,此時就會出現票數同時拿到 if(numberKey <= 0) { flag = false; return; } } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->"+numberKey--); } } private synchronized void test3() { while(true) { if(numberKey <= 0) { return; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->"+numberKey--); } } private void test2() { while(flag) { synchronized((Integer)numberKey) { //由於對象爲flag 和numberkey,鎖住一個對象是不安全的, if(numberKey <= 0) { flag = false; return; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->"+numberKey--); } } } private void test() { while(true) { synchronized(this) { //線程安全,由於this對象包括了numberkey和flag if(numberKey <= 0) { return; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->"+numberKey--); } } } }
銀行取錢,鎖定銀行帳號:app
package com.wxh.syn; /** * synchronized 鎖執行完畢以後,才釋放鎖 * 由於銀河存款100,可悲啊取走80後,剩餘20不達到happy的他取錢90要求,return * @author Administrator * 代碼塊:更加精細控制 */ public class UnsafeTest { public static void main(String[] args) { Account1 account = new Account1(170, "結婚禮金"); Drawing1 you = new Drawing1(account, 80, "可悲啊"); Drawing1 wif = new Drawing1(account, 90, "happy的他"); you.start(); wif.start(); } } //建立銀行帳戶 class Account1{ int money; String name; public Account1(int money, String name) { this.money = money; this.name = name; } } //模擬取款 class Drawing1 extends Thread{ Account1 account; //取錢的帳戶 int Outmoney; //取得錢數 int pagemoney; //取得總數 public Drawing1(Account1 account, int outmoney,String name) { super(name); this.account = account; Outmoney = outmoney; } public void run() { test(); } //目標鎖定不對,應該鎖定對象(銀行帳號account) private void test() { if(account.money <= 0) { //提升性能的細節,由於每次線程進來都須要判斷鎖是否執行完以後再判斷 return; //而這一步提早判斷當銀行餘額爲0時,不須要執行如下代碼,大大提升了併發量。 } synchronized(account) { if(account.money -Outmoney <0) { return; } // try { // Thread.sleep(1000); // } catch (InterruptedException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } account.money -= Outmoney; //帳戶餘額 pagemoney = Outmoney; System.out.println(this.getName()+"--->帳戶餘額"+account.money); System.out.println(this.getName()+"--->口袋金額"+pagemoney); } //synchronized 鎖執行完畢以後,才釋放鎖 } }