java多线程操作例子-(以银行存钱取钱为例)

     以前一直没有养成一个梳理知识的习惯,今天复习到多线程的知识的,想到的经典的存钱取钱多线程同步机制,今天在这里梳理下,错的地方请各位大佬指正

1:多线程同步的方法

1:使用synchronized关键字修饰方法和代码块(这就是两种了)

2:使用特殊变量volatitle关键字修饰

3:JAVA5.0引入了重入锁机制


1: 先看不引入锁我们存钱取钱会发生什么

    1.1 :新建一个银行类Bank


package testThread;

import org.omg.CORBA.PUBLIC_MEMBER;
import org.w3c.dom.css.Counter;
/**
 * 一本正经的假装银行
 *
 */
public class Bank {
	//账户余额
	private int sum=0;
	
	/**
	 * 存钱
	 * @param money
	 */
	public synchronized void addMoney(int money) {
		sum+=money;
		System.out.println(System.currentTimeMillis()+"存进"+money);
	}
	
	/**
	 * 取钱
	 */
	public void subMoney(int money)
	{
		if(sum-money<0)
		{
			System.out.println("余额不足");
			return;
		}else {
			sum-=money;
			System.out.println(System.currentTimeMillis()+"取出"+money);
		}
		
	}
	
	/**
	 * 查询余额
	 */
	public void lookMoney()
	{
	System.out.println("账户余额"+sum);	
	}

}

2:建立顾客完成存钱取钱的操作

package testThread;
/**
 * 主方法完成.假装两个存钱和取钱的的(大佬有钱,一直存取)
 */
public class TestMain {
	 public static void main(String args[]){  
	        final Bank bank=new Bank();  
	        Thread tadd=new Thread(new Runnable() {  
	            @Override  
	            public void run() {  
	                // TODO Auto-generated method stub  
	                while(true){  
	                    try {  
	                        Thread.sleep(1000);  
	                    } catch (InterruptedException e) {  
	                        // TODO Auto-generated catch block  
	                        e.printStackTrace();  
	                    }  
	                    bank.addMoney(100);  
	                    bank.lookMoney();  
	                }  
	            }  
	        });  

	        Thread tsub = new Thread(new Runnable() {  

	            @Override  
	            public void run() {  
	                // TODO Auto-generated method stub  
	                while(true){  
	                    bank.subMoney(100);  
	                    bank.lookMoney();  
	                    try {  
	                        Thread.sleep(1000);  
	                    } catch (InterruptedException e) {  
	                        // TODO Auto-generated catch block  
	                        e.printStackTrace();  
	                    }     
	                }  
	            }  
	        });  
	        tsub.start();  
	        tadd.start();  
	    }  
}
1.3:截图
java多线程操作例子-(以银行存钱取钱为例)_第1张图片

结果分析:我电脑CPU处理的太快了,一直没看到真正想要的结果真实的结果类似这个

余额不足  
账户余额:0  

余额不足  
账户余额:100  
(有一百你不让我取,这个货)
1441792010959存进:100  
账户余额:100  

为什么出现这样的结果呢,这个就是多线程同时操作同一个资源,没有用同步机制,发生了小问题

2:引入synchronized关键字bank类

package testThread;

import org.omg.CORBA.PUBLIC_MEMBER;
import org.w3c.dom.css.Counter;
/**
 * 假装银行
 *
 */
public class Bank {
	//账户余额
	private int sum=0;
	
	/**
	 * 存钱
	 * @param money
	 */
	public synchronized void addMoney(int money) {
		sum+=money;
		System.out.println(System.currentTimeMillis()+"存进"+money);
	}
	
	/**
	 * 取钱
	 */
	public synchronized void subMoney(int money)
	{
		if(sum-money<0)
		{
			System.out.println("余额不足");
			return;
		}else {
			sum-=money;
			System.out.println(System.currentTimeMillis()+"取出"+money);
		}
		
	}
	
	/**
	 * 查询余额
	 */
	public void lookMoney()
	{
	System.out.println("账户余额"+sum);	
	}

}


在看看运行结果

java多线程操作例子-(以银行存钱取钱为例)_第2张图片

咳咳,其实是上面的图...........懂就好(synchronized 当然也可以修饰静态的方法,不过调用它的时候会封锁整个类);

3:synchronized修饰的代码块

package testThread;

import org.omg.CORBA.PUBLIC_MEMBER;
import org.w3c.dom.css.Counter;
/**
 * 假装银行
 *
 */
public class Bank {
	//账户余额
	private int sum=0;
/**
	 * 存钱
	 * @param money
	 */
	public  void addMoney(int money) {
		synchronized(this)
		{
			sum+=money;
			System.out.println(System.currentTimeMillis()+"存进"+money);
		}
	}

/**
	 * 取钱
	 */
	public void subMoney(int money)
	{
		 synchronized(this)
		 {
		     if(sum-money<0)
			{
			System.out.println("余额不足");
			return;
			}else {
				sum-=money;
				System.out.println(System.currentTimeMillis()+"取出"+money);
			} 
		 }
	
	}
	/**
	 * 查询余额
	 */
	public void lookMoney()
	{
	System.out.println("账户余额"+sum);	
	}

}

结果和上面的一样

4:使用volatitle关键字

package testThread;
/**
 * 假装
 *
 */
public class Bank {
	//账户余额
	private volatile int sum=0;
	
	/**
	 * 存钱
	 * @param money
	 */
	public void addMoney(int money) {
		sum+=money;
		System.out.println(System.currentTimeMillis()+"存进"+money);
	}
	
	/**
	 * 取钱
	 */
	public void subMoney(int money)
	{
		if(sum-money<0)
		{
			System.out.println("余额不足");
			return;
		}else {
			sum-=money;
			System.out.println(System.currentTimeMillis()+"取出"+money);
		}
		
	}
	
	/**
	 * 查询余额
	 */
	public void lookMoney()
	{
	System.out.println("账户余额"+sum);	
	}

}

结果分析

余额不足  
账户余额:0  

余额不足  
账户余额:100  

1441792010959存进:100  
账户余额:100  

1441792011960取出:100  
账户余额:0  

1441792011961存进:100  
账户余额:100

结果又tmd不让取了,,这个是为啥呢

因为volatitle不能保证原子操作导致,每次线程要访问volatitle变量都是从内存中去读的,而是不是从缓存中读的,这就保证每个线程访问的变量是一样的,这就保证了同步

5:使用重入锁实现线程同步

啥也不说,老规矩,上代码

package testThread;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Bank{
	//账户余额
	private  int sum=0;
	
	//1.1: 我们需要先申明这个锁
	private Lock lock=new ReentrantLock();
	/**
	 * 存钱
	 * @param money
	 */
	public void addMoney(int money) {
		//1.2上锁
		lock.lock();
		try {
			sum+=money;
			System.out.println(System.currentTimeMillis()+"存进"+money);
		} catch (Exception e) {
			// TODO: handle exception
		}finally{
			//1.3解锁
			lock.unlock();
		}
		
	}
	
	/**
	 * 取钱
	 */
	public void subMoney(int money)
	{
		//1.1上锁
		lock.lock();
		try {
			if(sum-money<0)
			{
				System.out.println("余额不足");
				return;
			}else {
				sum-=money;
				System.out.println(System.currentTimeMillis()+"取出"+money);
			}
		} finally{
			//接锁
			lock.unlock();
		}
		
		
	}
	
	/**
	 * 查询余额
	 */
	public void lookMoney()
	{
	System.out.println("账户余额"+sum);	
	}

}

结果分析:

和上上图结果一样,不贴了,老铁....

我们一般同步用synchronized,如果你想要用高级一点的,用lock,但别忘了释放一下,不理会发生死锁的哦,同学









你可能感兴趣的:(java面试题总结,java基础知识)