初探多线程之线程同步

1.synchronized同步代码块

   synchronized(obj){

          .....

         //同步代码块的代码

   }

直接对obj对象同步监听,任何线程在修改指定的资源之前,首先对该资源加锁,在加锁期间其他线程无法修改该资源。

2.synchronized同步方法

  1)类里的对象可以被多线程安全访问

 

public synchronized void  draw(double drawAmount){
		if (this.balance >= drawAmount) {
			System.out.println(Thread.currentThread().getName() + "取钱成功!吐出现金:" + drawAmount);

			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			this.balance = this.balance - drawAmount;
			System.out.println("\t余额为:" + balance);
		} else {
			System.out.println(Thread.currentThread().getName() + "取钱失败,余额不足!");
		}
	}

 总结:

 

    1)synchronized可修饰方法,可修饰代码块,但不能修饰构造器,属性。

    2)不要对线程安全的所有方法都进行同步。

3.同步锁(Lock)

   显式加锁,显式解锁

   ReentrantLock(可重入锁):一个线程可以对已被加锁的ReentrantLock锁再次加锁,ReentrantLock对象会维持一个计数器来追踪lock()方法的嵌套调用。

  

public class Account {
	
	private final ReentrantLock lock = new ReentrantLock();

	public void draw(double drawAmount) {
		//上锁
		lock.lock();
		try {
			......//操作代码
		} finally {
			//解锁
			lock.unlock();
		}
	}

}

 

   4.死锁问题

     当两个线程互相等待对方释放同步监视器时就会发生死锁,当陷入死锁,所有线程处于阻塞状态,无法继续。

    四个必要条件:

    1 )互斥条件:指 进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它 进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
    2 )请求和保持条件:指 进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它 进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
    3 )不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
    4 )环路等待条件:指在发生死锁时,必然存在一个 进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
    传统的线程通信:
       wait():导致当前线程等待
       notify():唤醒等待线程中的单个线程
       notifyAll():唤醒等待线程中的所有线程
public class Account {
	private String accountNo;
	private double balance;
	private boolean flag = false;

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

	public int hashCode() {
		return accountNo.hashCode();
	}

	public boolean equals(Object object) {
		if (this == object) {
			return true;
		}

		if (object != null && object.getClass() == this.getClass()) {
			Account account = (Account) object;
			return account.getAccountNo().equals(account);
		}

		return false;
	}

	public String getAccountNo() {
		return accountNo;
	}

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

	public double getBalance() {
		return balance;
	}

	public synchronized void draw(double drawAmount) {
		try {
			if (!flag) {
				wait();
			} else {
				if (this.balance >= drawAmount) {
					System.out.println(Thread.currentThread().getName()
							+ "取钱成功!吐出现金:" + drawAmount);

					try {
						Thread.sleep(1);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}

					this.balance = this.balance - drawAmount;
					System.out.println("\t余额为:" + balance);
					
					flag = false;
					notifyAll();
				} else {
					System.out.println(Thread.currentThread().getName()
							+ "取钱失败,余额不足!");
				}
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public synchronized void deposit(double depositAmount) {
		try {
			if (flag) {
				wait();
			} else {
				System.out.println(Thread.currentThread().getName() + "存款:"
						+ depositAmount);

				balance += depositAmount;
				System.out.println("\t余额为:" + balance);
				flag = true;
				notifyAll();
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}
 
    使用Condition类控制线程通信
    Condition实例的方法:
       await():类似于隐式同步监视器上的wait()方法
       signal():类似于notify()方法
       signalAll():类似于notifyAll()方法
public class Account {
	private String accountNo;
	private double balance;
	private boolean flag = false;

	private final Lock lock = new ReentrantLock();
	private final Condition condition = lock.newCondition();

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

	public int hashCode() {
		return accountNo.hashCode();
	}

	public boolean equals(Object object) {
		if (this == object) {
			return true;
		}

		if (object != null && object.getClass() == this.getClass()) {
			Account account = (Account) object;
			return account.getAccountNo().equals(account);
		}

		return false;
	}

	public String getAccountNo() {
		return accountNo;
	}

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

	public double getBalance() {
		return balance;
	}

	public void draw(double drawAmount) {
		lock.lock();
		try {
			if (!flag) {
				condition.await();
			} else {
				if (this.balance >= drawAmount) {
					System.out.println(Thread.currentThread().getName() + "取钱成功!吐出现金:" + drawAmount);
					try {
						Thread.sleep(1);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}

					this.balance = this.balance - drawAmount;
					System.out.println("\t余额为:" + balance);

					flag = false;
					condition.signalAll();
				} else {
					System.out.println(Thread.currentThread().getName() + "取钱失败,余额不足!");
				}
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public synchronized void deposit(double depositAmount) {
		lock.lock();
		try {
			if (flag) {
				condition.await();
			} else {
				System.out.println(Thread.currentThread().getName() + "存款:" + depositAmount);

				balance += depositAmount;
				System.out.println("\t余额为:" + balance);
				flag = true;
				condition.signalAll();
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

}
     显式和隐式线程通信

你可能感兴趣的:(java)