线程同步和锁

多个线程访问同一个数据时,容易出现线程安全问题。如:经典的银行取钱问题。

为阻止两条线程对同一个共享资源的并发访问引起的问题,

可以:

1、使用同步监视器的通用方法就是同步代码块。

Synchronized(obj){
    //同步代码块
}

其中obj就是同步监视器,必须要获得对同步监视器的锁定才能执行同步代码块。

2、同步方法。

就是使用Synchronized修饰的方法,同步方法无需显示指定同步监视器,同步方法的同步监视器是this。

import java.util.concurrent.locks.ReentrantLock;

public class Account {

	private String accountNo;
	private double balance;

	private final ReentrantLock lock = new ReentrantLock();//可重入锁

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

	public void draw(double drawAmount) // public synchronized void draw(doubledrawAmount) 同步方法
	{
		lock.lock();
		try {
			if (balance >= drawAmount) {
				try {
					Thread.sleep(1);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
				balance -= drawAmount;
				System.out.println("余额为啊:" + balance);
			} else {
				System.out.println("余额不足啊。");
			}
		} finally {
			lock.unlock();
		}
	}

	public String getAccountNo() {
		return accountNo;
	}

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

	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}

	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;
	}
}
package ex1;
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);//直接调用account对象的draw方法执行,该方法用synchronized修饰,变成同步方法

       /*synchronized(account)//使用account作为同步监视器的方法用
        {

            if (account.getBalance() >=drawAmount)
            {
                try
                {
                    Thread.sleep(1);

                } catch (InterruptedException ex)
                {
                    ex.printStackTrace();
                }
               account.setBalance(account.getBalance() - drawAmount);
                System.out.println("取钱成功。余额:" +account.getBalance());
            } else
            {
                System.out.println("余额不足。");
           }
        }*/

   }
}

3、同步锁(Lock)

Lock提供比Synchronized更广泛的锁机制,它是控制多个线程对共享资源进行访问的工具。锁对共享资源的独占访问。每次只能有一个线程加锁。常用的ReentrantLock(可重入锁)。

class X {
	// 定义锁对象
	private final ReentrantLock lock = new ReentrantLock();
	// 定义需要保证线程安全的方法
	public void m() {
		// 加锁
		lock.lock();
		try {
			// 需要保证安全的代码
		}
		// 使用finally块来保证释放锁
		finally {
			lock.unlock();
		}
	}
}

4、死锁

当两个线程相互等待对方释放同步监视器时就会发生死锁,一旦发生死锁程序不会发生任何异常和提示,只是出于阻塞状态,无法继续。

猜你喜欢

转载自blog.csdn.net/terry8000/article/details/80945821