Java多線程-新特徵-鎖

來源:互聯網
上載者:User

標籤:

在Java5中,專門提供了鎖對象,利用鎖可以方便的實現資源的封鎖,用來控制對競爭資源並發訪問的控制,這些內容主要集中在java.util.concurrent.locks 包下面,裡面有三個重要的介面Condition、Lock、ReadWriteLock。

Condition: 
Condition 將 Object 監視器方法(wait、notify 和 notifyAll)分解成截然不同的對象,以便通過將這些對象與任意 Lock 實現組合使用,為每個對象提供多個等待 set (wait-set)。

Lock: 
Lock 實現提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作。

ReadWriteLock: 
ReadWriteLock 維護了一對相關的鎖定,一個用於唯讀操作,另一個用於寫入操作。


有關鎖的介紹,API文檔解說很多,看得很煩,還是看個例子再看文檔比較容易理解。

package cn.thread;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/** *  *  * @author 林計欽 * @version 1.0 2013-7-25 上午10:33:37 */public class LockTest {    public static void main(String[] args) {        LockTest test = new LockTest();        // 建立並發訪問的賬戶        MyCount myCount = test.new MyCount("95599200901215522", 10000);        // 建立一個鎖對象        Lock lock = new ReentrantLock();        // 建立一個線程池        ExecutorService pool = Executors.newCachedThreadPool();        // 建立一些並發訪問使用者,一個信用卡,存的存,取的取,好熱鬧啊        User u1 = test.new User("張三", myCount, -4000, lock);        User u2 = test.new User("張三他爹", myCount, 6000, lock);        User u3 = test.new User("張三他弟", myCount, -8000, lock);        User u4 = test.new User("張三", myCount, 800, lock);        // 線上程池中執行各個使用者的操作        pool.execute(u1);        pool.execute(u2);        pool.execute(u3);        pool.execute(u4);        // 關閉線程池        pool.shutdown();    }    /**     * 信用卡的使用者     */    class User implements Runnable {        private String name; // 使用者名稱        private MyCount myCount; // 所要操作的賬戶        private int iocash; // 操作的金額,當然有正負之分了        private Lock myLock; // 執行操作所需的鎖對象        User(String name, MyCount myCount, int iocash, Lock myLock) {            this.name = name;            this.myCount = myCount;            this.iocash = iocash;            this.myLock = myLock;        }        public void run() {            String string;            if(iocash>0){                string="存款";            }else{                string="取款";            }                        // 擷取鎖            myLock.lock();            // 執行現金業務            System.out.println(name + "正在操作" + myCount + "賬戶," +                     string+"金額為" + iocash + ",當前金額為" + myCount.getCash());            myCount.setCash(myCount.getCash() + iocash);            System.out.println(name + "操作" + myCount + "賬戶成功,"+                     string + "金額為" + iocash + ",當前金額為" + myCount.getCash());            System.out.println("============");            // 釋放鎖,否則別的線程沒有機會執行了            myLock.unlock();        }    }    /**     * 信用卡賬戶,可隨意透支     */    class MyCount {        private String oid; // 帳號        private int cash; // 賬戶餘額        MyCount(String oid, int cash) {            this.oid = oid;            this.cash = cash;        }        public String getOid() {            return oid;        }        public void setOid(String oid) {            this.oid = oid;        }        public int getCash() {            return cash;        }        public void setCash(int cash) {            this.cash = cash;        }        @Override        public String toString() {            return "MyCount{" + "帳號=‘" + oid + ‘\‘‘ + ", 餘額=" + cash + ‘}‘;        }    }}
張三正在操作MyCount{帳號=‘95599200901215522‘, 餘額=10000}賬戶,取款金額為-4000,當前金額為10000張三操作MyCount{帳號=‘95599200901215522‘, 餘額=6000}賬戶成功,取款金額為-4000,當前金額為6000============張三他弟正在操作MyCount{帳號=‘95599200901215522‘, 餘額=6000}賬戶,取款金額為-8000,當前金額為6000張三他弟操作MyCount{帳號=‘95599200901215522‘, 餘額=-2000}賬戶成功,取款金額為-8000,當前金額為-2000============張三他爹正在操作MyCount{帳號=‘95599200901215522‘, 餘額=-2000}賬戶,存款金額為6000,當前金額為-2000張三他爹操作MyCount{帳號=‘95599200901215522‘, 餘額=4000}賬戶成功,存款金額為6000,當前金額為4000============張三正在操作MyCount{帳號=‘95599200901215522‘, 餘額=4000}賬戶,存款金額為800,當前金額為4000張三操作MyCount{帳號=‘95599200901215522‘, 餘額=4800}賬戶成功,存款金額為800,當前金額為4800============

從上面的輸出可以看到,利用鎖對象太方便了,比直接在某個不知情的對象上用鎖清晰多了。

但一定要注意的是,在擷取了鎖對象後,用完後應該儘快釋放鎖,以便別的等待該鎖的線程有機會去執行。

 

在上文中提到了Lock介面以及對象,使用它,很優雅的控制了競爭資源的安全訪問,但是這種鎖不區分讀寫,稱這種鎖為普通鎖。為了提高效能,Java提供了讀寫鎖,在讀的地方使用讀鎖,在寫的地方使用寫鎖,靈活控制,在一定程度上提高了程式的執行效率。

Java中讀寫鎖有個介面java.util.concurrent.locks.ReadWriteLock,也有具體的實現ReentrantReadWriteLock,詳細的API可以查看JavaAPI文檔。

下面這個例子是在文例子的基礎上,將普通鎖改為讀寫鎖,並添加賬戶餘額查詢的功能,代碼如下:

package cn.thread;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock;/** * 讀寫鎖 *  * @author 林計欽 * @version 1.0 2013-7-25 上午10:33:37 */public class WriteReadLockTest {    public static void main(String[] args) {        WriteReadLockTest test = new WriteReadLockTest();        // 建立並發訪問的賬戶        MyCount myCount = test.new MyCount("95599200901215522", 10000);        // 建立一個鎖對象        ReadWriteLock lock = new ReentrantReadWriteLock(false);        // 建立一個線程池        ExecutorService pool = Executors.newFixedThreadPool(2);        // 建立一些並發訪問使用者,一個信用卡,存的存,取的取,好熱鬧啊        User u1 = test.new User("張三", myCount, -4000, lock, false);        User u2 = test.new User("張三他爹", myCount, 6000, lock, false);        User u3 = test.new User("張三他弟", myCount, -8000, lock, false);        User u4 = test.new User("張三", myCount, 800, lock, false);        User u5 = test.new User("張三他爹", myCount, 0, lock, true);        // 線上程池中執行各個使用者的操作        pool.execute(u1);        pool.execute(u2);        pool.execute(u3);        pool.execute(u4);        pool.execute(u5);        // 關閉線程池        pool.shutdown();    }    /**     * 信用卡的使用者     */    class User implements Runnable {        private String name; // 使用者名稱        private MyCount myCount; // 所要操作的賬戶        private int iocash; // 操作的金額,當然有正負之分了        private ReadWriteLock myLock; // 執行操作所需的鎖對象        private boolean ischeck; // 是否查詢        User(String name, MyCount myCount, int iocash, ReadWriteLock myLock, boolean ischeck) {            this.name = name;            this.myCount = myCount;            this.iocash = iocash;            this.myLock = myLock;            this.ischeck = ischeck;        }        public void run() {            if (ischeck) {                // 擷取讀鎖                myLock.readLock().lock();                System.out.println("讀:" + name + "正在查詢" + myCount + "賬戶,當前金額為" + myCount.getCash());                // 釋放讀鎖                myLock.readLock().unlock();            } else {                // 擷取寫鎖                myLock.writeLock().lock();                // 執行現金業務                System.out.println("寫:" + name + "正在操作" + myCount + "賬戶,金額為" + iocash + ",當前金額為"                        + myCount.getCash());                myCount.setCash(myCount.getCash() + iocash);                System.out.println("寫:" + name + "操作" + myCount + "賬戶成功,金額為" + iocash + ",當前金額為"                        + myCount.getCash());                // 釋放寫鎖                myLock.writeLock().unlock();            }        }    }    /**     * 信用卡賬戶,可隨意透支     */    class MyCount {        private String oid; // 帳號        private int cash; // 賬戶餘額        MyCount(String oid, int cash) {            this.oid = oid;            this.cash = cash;        }        public String getOid() {            return oid;        }        public void setOid(String oid) {            this.oid = oid;        }        public int getCash() {            return cash;        }        public void setCash(int cash) {            this.cash = cash;        }        @Override        public String toString() {            return "MyCount{" + "oid=‘" + oid + ‘\‘‘ + ", cash=" + cash + ‘}‘;        }    }}
寫:張三正在操作MyCount{oid=‘95599200901215522‘, cash=10000}賬戶,金額為-4000,當前金額為10000寫:張三操作MyCount{oid=‘95599200901215522‘, cash=6000}賬戶成功,金額為-4000,當前金額為6000寫:張三他爹正在操作MyCount{oid=‘95599200901215522‘, cash=6000}賬戶,金額為6000,當前金額為6000寫:張三他爹操作MyCount{oid=‘95599200901215522‘, cash=12000}賬戶成功,金額為6000,當前金額為12000寫:張三正在操作MyCount{oid=‘95599200901215522‘, cash=12000}賬戶,金額為800,當前金額為12000寫:張三操作MyCount{oid=‘95599200901215522‘, cash=12800}賬戶成功,金額為800,當前金額為12800寫:張三他弟正在操作MyCount{oid=‘95599200901215522‘, cash=12800}賬戶,金額為-8000,當前金額為12800寫:張三他弟操作MyCount{oid=‘95599200901215522‘, cash=4800}賬戶成功,金額為-8000,當前金額為4800讀:張三他爹正在查詢MyCount{oid=‘95599200901215522‘, cash=4800}賬戶,當前金額為4800

在實際開發中,最好在能用讀寫鎖的情況下使用讀寫鎖,而不要用普通鎖,以求更好的效能。

Java多線程-新特徵-鎖

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.