欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

线程的同步

程序员文章站 2024-03-01 18:49:52
...

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

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

/**
 * 线程不安全的网络抢票
 *
 */
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 + "张票!");
			}
		}
	}
}