Java初级-多线程-同步(Synchronized)

本文介绍了Java中的同步编程模式,旨在确保多线程环境中的数据安全性。通过示例展示了未同步时可能出现的问题,并阐述了使用synchronized关键字进行线程同步的重要性,以防止对共享资源的错误并发操作。

一、基本概念

   异步编程模式与同步编程模式

    异步编程模式:t1线程执行t1的,t2线程执行t2的.两个线程谁也不等谁。

    同步编程模式:这里的同指的是协同。t1和t2线程执行的时候,t1必须等t2线程执行完毕之后才能执行。同步机制使程序等同单线程。

二、java多线程同步的目的

    为了数据的安全,暂时放弃执行的效率

三、线程同步的条件

       1.多线程环境
        2.共享同一资源

        3.数据涉及到修改操作

四、下面例子演示了在线程不同步时会出现的问题

package com.gdzy.SynchronizedTest;
/**
 * 此程序模拟一个银行账户取款的操作, 有多个取款线程同时对一个账户进行操作, 在不使用线程同步时会出现错误
 */
public class SynchronizedTest01 {


	public static void main(String[] args) {     //主程序
		
		Account acc = new Account("张三",10000);
		Withdrawal w1 = new Withdrawal(acc);
		
		Thread t1 = new Thread(w1);
		Thread t2 = new Thread(w1);
		Thread t3 = new Thread(w1);
		Thread t4 = new Thread(w1);
		Thread t5 = new Thread(w1);
		Thread t6 = new Thread(w1);
		t1.setName("取款人--1");
		t2.setName("取款人--2");
		t3.setName("取款人--3");
		t4.setName("取款人--4");
		t5.setName("取款人--5");
		t6.setName("取款人--6");
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
		t6.start();
	}


}
//定义一个账户类
class Account{
	
	private String accName;  //定义一个账户名
	private double balance;  //定义账户余额
	//无参构造
	public Account(){        
		
	}
	//有参构造
	public Account(String accName,double balance){  
		this.accName = accName;
		this.balance = balance;
	}
	 //get set方法
	public String getAccName(){        
		return this.accName;
	}
	public void setAccName(String accName){
		this.accName = accName;
	}
	
	public double getBalance(){
		return this.balance;
	}
	public void setBalance(double balance){
		this.balance = balance;
	}
	//提供一个更新账户取款后余额的方法  
	public void updateAcc(double money){      
		double remain = balance - money;


		this.balance = remain;
	}
	
}
//定义一个取款操作的线程
class Withdrawal implements Runnable{
	// 将取款类 与 账户类关联起来
	Account acc;
	//无参构造
	public Withdrawal(){
		
	}
	//有参构造
	public Withdrawal(Account acc){
		this.acc = acc;
	}
	//重写run方法, 完成一次取款1000后更新并输出账户余额
	public void run() {
		acc.updateAcc(1000);
		System.out.println(Thread.currentThread()+"---取款成功,帐户余额为: "+acc.getBalance());
		
	}
	
}

代码运行后, 会发现由于多个线程对同一账户同时进行取款操作, 导致余额刷新出现的混乱

Thread[取款人--3,5,main]---取款成功,帐户余额为: 7000.0
Thread[取款人--4,5,main]---取款成功,帐户余额为: 6000.0
Thread[取款人--2,5,main]---取款成功,帐户余额为: 7000.0
Thread[取款人--6,5,main]---取款成功,帐户余额为: 4000.0
Thread[取款人--5,5,main]---取款成功,帐户余额为: 5000.0
Thread[取款人--1,5,main]---取款成功,帐户余额为: 7000.0

在java中多线程中,由于同时对同一资源同时进行操作而引起的错误,为了解决这个问题,引入synchronized关键字, 即在线程代码中, 对操作同一资源的方法或对方法中操作同一资源的语句加锁(synchronized)。

如下代码可解决实际的问题:

package com.gdzy.SynchronizedTest;


/**
 * 此程序模拟一个银行账户取款的操作, 有多个取款线程同时对一个账户进行操作, 在不使用线程同步时会出现错误
 */
public class SynchronizedTest02 {

	public static void main(String[] args) {     //主程序
		
		Account02 acc = new Account02("张三",10000);
		
		Withdrawal02 w1 = new Withdrawal02(acc);
		
		Thread t1 = new Thread(w1);
		Thread t2 = new Thread(w1);
		Thread t3 = new Thread(w1);
		Thread t4 = new Thread(w1);
		Thread t5 = new Thread(w1);
		Thread t6 = new Thread(w1);
		t1.setName("取款人--1");
		t2.setName("取款人--2");
		t3.setName("取款人--3");
		t4.setName("取款人--4");
		t5.setName("取款人--5");
		t6.setName("取款人--6");
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
		t6.start();

	}

}
//定义一个账户类
class Account02{
	
	private String accName;  //定义一个账户名
	private double balance;  //定义账户余额
	//无参构造
	public Account02(){        
		
	}
	//有参构造
	public Account02(String accName,double balance){  
		this.accName = accName;
		this.balance = balance;
	}
	 //get set方法
	public String getAccName(){        
		return this.accName;
	}
	public void setAccName(String accName){
		this.accName = accName;
	}
	
	public double getBalance(){
		return this.balance;
	}
	public void setBalance(double balance){
		this.balance = balance;
	}
	//提供一个更新账户取款后余额更新的方法 
	public  void updateAcc(double money){ 
		
		//同步之后还需要加上Thread.sleep方法, 使之具有运行的时间????

		double remain = balance - money;

		this.balance = remain;
		//setBalance(remain);  //也可以通过set方法来设置余额
		
		// 第二种同步(锁)           第一种相当于锁大门, 第二种相当于锁房间
	
	}
	
}
//定义一个取款操作的线程
class Withdrawal02 implements Runnable{
	// 将取款类 与 账户类关联起来
	Account02 acc;
	//无参构造
	public Withdrawal02(){
		
	}
	//有参构造
	public Withdrawal02(Account02 acc){
		this.acc = acc;
	}
	//重写run方法, 完成一次取款1000后更新并输出账户余额
	
	public synchronized void run(){  //再需要同步(加锁)的方法前加上synchronized关键字, 也可以在内部写一个同步的代码块
		acc.updateAcc(1000);
				
		System.out.println(Thread.currentThread()+":取款成功,帐户余额为: "+acc.getBalance());
//		也可通过下面加synchronized代码块的方式, 将对同一资源操作的代码进行加锁限定
//		synchronized(this){
//			
//				acc.updateAcc(1000);
//
//		
//			System.out.println(Thread.currentThread()+":取款成功,帐户余额为: "+acc.getBalance());
//		}
	}
	
}

运行后得到的结果如下:

Thread[取款人--1,5,main]:取款成功,帐户余额为: 9000.0
Thread[取款人--6,5,main]:取款成功,帐户余额为: 8000.0
Thread[取款人--5,5,main]:取款成功,帐户余额为: 7000.0
Thread[取款人--4,5,main]:取款成功,帐户余额为: 6000.0
Thread[取款人--3,5,main]:取款成功,帐户余额为: 5000.0
Thread[取款人--2,5,main]:取款成功,帐户余额为: 4000.0







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值