程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Lock同步鎖--線程同步,lock同步--線程

Lock同步鎖--線程同步,lock同步--線程

編輯:JAVA綜合教程

Lock同步鎖--線程同步,lock同步--線程


Lock-同步鎖

Lock是java5提供的一個強大的線程同步機制--通過顯示定義同步鎖對象來實現同步。Lock可以顯示的加鎖、解鎖。每次只能有一個線程對lock對象加鎖。

Lock有ReadLock、WriteLock、ReentrantLock(可重入鎖)

常用的就是ReentrantLock。代碼如下:

代碼邏輯:Account賬戶類,實現取錢的同步方法、DrawThread取錢的線程

Account:

package lock.reentrantlock2;
import java.util.concurrent.locks.*;

/**
 *賬戶類,需保持同步
 */
public class Account
{
	//定義鎖對象
	private final ReentrantLock lock = new ReentrantLock();
	private String accountNo;
	private double balance;


	public Account(){}

	public Account(String accountNo , double balance)
	{
		this.accountNo = accountNo;
		this.balance = balance;
	}

	public void setAccountNo(String accountNo)
	{
		this.accountNo = accountNo;
	}
	public String getAccountNo()
	{
		 return this.accountNo;
	}

	public double getBalance()
	{
		 return this.balance;
	}
	public void draw(double drawAmount)
	{
		lock.lock();
		try
		{
			//賬戶余額大於取錢數目
			if (balance >= drawAmount)
			{
				//吐出鈔票
				System.out.println(Thread.currentThread().getName() + 
					"取錢成功!吐出鈔票:" + drawAmount);
				try
				{
					Thread.sleep(1);			
				}
				catch (InterruptedException ex)
				{
					ex.printStackTrace();
				}
				//修改余額
				balance -= drawAmount;
				System.out.println("\t余額為: " + balance);
			}
			else
			{
				System.out.println(Thread.currentThread().getName() +
					"取錢失敗!余額不足!");
			}			
		}
		finally
		{
			lock.unlock();
		}
	}

	public int hashCode()
	{
		return accountNo.hashCode();
	}
	public boolean equals(Object obj)
	{
		if (obj != null && obj.getClass() == Account.class)
		{
			Account target = (Account)obj;
			return target.getAccountNo().equals(accountNo);
		}
		return false;
	}
}

  DrawThread:

package lock.reentrantlock2;

/**
 * 調用account取錢
 * 
 */

public class DrawThread extends Thread
{
	//模擬用戶賬戶
	private Account account;
	//當前取錢線程所希望取的錢數
	private double drawAmount;

	public DrawThread(String name , Account account , 
		double drawAmount)
	{
		super(name);
		this.account = account;
		this.drawAmount = drawAmount;
	}

	//當多條線程修改同一個共享數據時,將涉及到數據安全問題。
	public void run()
	{
		account.draw(drawAmount);
	}
}

  TestDraw:

package lock.reentrantlock2;

/**
 
 */
public class TestDraw
{
    public static void main(String[] args) 
    {
		//創建一個賬戶
		Account acct = new Account("1234567" , 1000);
		//模擬兩個線程對同一個賬戶取錢
		new DrawThread("甲" , acct , 800).start();
		new DrawThread("乙" , acct , 800).start();
    }
}
 

  運行結果:

甲取錢成功!吐出鈔票:800.0
余額為: 200.0
乙取錢失敗!余額不足!

 

使用Lock同步與同步方法很相似,都是“加鎖--修改公共變量--釋放鎖”的模式,代碼很容易看懂。兩個線程對應一個Account對象,保證了兩個線程對應一個lock對象,保證了同一時刻只有一個線程進入臨界區。Lock還包含太容易Lock(),以及試圖獲取可中斷鎖的lockInterruptibly(),獲取超時失效鎖的tryLock(long,TimeUnit)等方法。

  ReentrantLock鎖具有可重入性可以對已被加鎖的ReentrantLock鎖再次加鎖,線程每次調用lock()加鎖後,必須顯示的調用unlock來釋放鎖,有幾個lock就對應幾個unlock。還有把unlock放在finally代碼塊中,Lock在發生異常時也是不釋放鎖的,所以在finally中釋放更安全。

只是對Lock簡單說明了下,為下一篇線程通信打基礎。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved