线程的同步

多线程共享数据引发的问题

用一个简单的例子来说,就是我们经常遇到的过年抢车票的问题,以前人们是去车站排队,先到先得,现在随着互联网的发展,我们可以在网上购票了,现在我们使用多线程来模拟抢票过程,每个人机会一样。
关键代码如下:

/**
 * 线程不安全的网络抢票
 *
 */
public class Site implements Runnable{
	private int count=10;  //记录剩余票数	
	private int num = 0;   //记录买到第几张票
	public void  run(){
		while(true){
			//没有余票时,跳出循环
			if(count<=0){
				break;
			}
			//第一步:修改数据
			num++;
			count--;
			try {
				Thread.sleep(500); //模拟网络延时
			} catch (InterruptedException e) {			
				e.printStackTrace();
			}			
			//第二步:显示信息
			System.out.println(Thread.currentThread().getName()+"抢到第"+num+"张票,剩余"+count+"张票!");			
		}
	}
}
//测试类
public class Test {
	public static void main(String[] args) {
		Site site = new Site();
		Thread person1= new Thread(site,"桃跑跑");
		Thread person2= new Thread(site,"抢票代理");
		Thread person3= new Thread(site,"黄牛党");
		System.out.println("********开始抢票********");
		person1.start();
		person2.start();
		person3.start();
	}
}

在这里插入图片描述
看结果显示如下问题:
不是从第一张票开始
存在多人抢到一张票的情况
有些票号没有被抢到

这些都是由于多个线程并发操作统一共享资源,带来的数据不安全问题,要解决这样的问题,我们就需要使用到线程同步。

线程同步的实现
什么是线程同步
当两个或多个线程需要访问同一资源时,需要以某种顺序来确保该资源某一时刻只能被一个线程使用,这就是线程同步

采用线程同步来控制线程的执行有两种方式,即同步带吗方法和同步代码块。这两种方法都是用synchronized关键字实现。

通过在方法申明中加入synchronized关键字实现同步方法,其语法如下:
访问修饰符 synchronized 返回类型 方法名(参数列表){//省略方法体…}
或者
synchronized 访问修饰符 返回类型 方法名(参数列表){//省略方法体…}

在语法中:
synchronized是同步关键字
访问修饰符是指public,private等。

使用同步方法解决上述代码,如下所示:

public class Site implements Runnable{
	private int count=10;  //记录剩余票数	
	private int num = 0;   //记录买到第几张票
	public void  run(){
		while(true){
			if(count<=0){
				break;
			}
			//第一步:修改数据
			num++;
			count--;
			try {
				Thread.sleep(500); //模拟网络延时
			} catch (InterruptedException e) {			
				e.printStackTrace();
			}			
			//第二步:显示信息
			System.out.println(Thread.currentThread().getName()+"抢到第"+num+"张票,剩余"+count+"张票!");			
		}
	}
}


同步方法的缺陷
如果将一个运行时间较长的方法声明称synchronized将会影响效率

同步代码块
语法:synchronized(syncObject){
//需要同步的代码
}
示例代码如下:

public class Site implements Runnable {
	private int count = 10; // 记录剩余票数
	private int num = 0; // 记录买到第几张票

	public void run() {
		while (true) {
			//同步代码块
			synchronized (this) {
				// 没有余票时,跳出循环
				if (count <= 0) {
					break;
				}
				// 第一步:修改数据
				num++;
				count--;
				try {
					Thread.sleep(500); // 模拟网络延时
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				// 第二步:显示信息
				System.out.println(Thread.currentThread().getName() + "抢到第"
						+ num + "张票,剩余" + count + "张票!");
			}
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值