线程的同步

发表时间:2017-05-09 13:30:46 浏览量( 22 ) 留言数( 0 )

学习目标:

1、了解Java的历史

2、为什么要学习Java语言

3、端正学习态度


学习过程:

一、什么是线程的同步

1、线程同步的意义。

线程的同步是为了保证代码的原子性,保证每个线程在调用对象同步方法独占的方法操作该对象。一段代码就好像一座独木桥,任何一个时刻,只能有一个人在桥上行走,程序中不能有多个线程同时在这两句代码之间执行,这就是线程同步。比如:银行的自动柜员机,一次只能一个人取钱,其他人必须排队。公司的打印机虽然是多台电脑共用的,但是每次也只能一台电脑在打印。

同步是以牺牲程序的性能为代价的。所以,如果确定程序没有安全性的问题,就没有必要使用同步。

2、同步的实现,使用synchronize关键字

我们将需要具有原子性的代码放入synchronize语句内,形成同步代码块。就可以保证线程安全了。每个对象都有一个标志位(锁旗标),该标志位有两个状态0、1,其开始状态为1,当执行synchronized(Object)语句后,Object对象的标志位变为0状态,直到执行完整个synchronized语句中的代码块后才又回到1状态。

一个线程执行到synchronized(Object)的时候,先检查Object对象的标志位,0表示有线程在执行,这个线程将暂时阻塞,让出CPU资源,直到另外线程执行完有关代码,将Object对象状态恢复到1状态,这个阻塞才被取消,然后线程开始执行,同时将Object对象的标志位变为0,防止其他线程再进入有关的同步代码块中。

当线程执行到synchronized的时候,如果得不到锁标记,这个线程会被加入到一个与该对象的锁标记相关连的等待线程池当中,等待锁标记。当线程执行完同步代码,就会释放锁标记。

synchronized有两种用法

(1)定义同步方法: synchronized  方法名称(同步){ 方法体 } ,使用这个方法对象都会同步。

(2)同步块,灵活锁住对象同步方法就等于锁住this:synchronized(对象){ 同步块 }

二、示例代码

下面我们模拟公司有一台打印机,有多个学生同时操作电脑,点击打印自己的成绩,如果不使用同步,打印机打印出来的结果将会错乱,然后我们改成使用同步后,再查看结果,打印机会打印一个学生后,再打印另外一个学生,有序的把所有的学生成绩打印出来。

1、先定义打印机类,暂时不实现同步,代码如下:

 /**
 * 打印机
 */
public class Print {
	
	public  void p(String name,int en,int math){
		System.out.print("姓名:"+name+":");
		System.out.println("数学成绩:"+math+",英语成绩:"+en);
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

2、实现学生打印操作类,每个操作类就是一个线程,该线程调用同一个打印对象实现打印。代码如下:

 public class StudentThread extends Thread {
	
	private Print print;
	private String name;
	private int en;
	private int math;
	
	public StudentThread(Print print,String name,int en,int math){
		this.print=print;
		this.name=name;
		this.en=en;
		this.math=math;
	}

	@Override
	public void run() {
		print.p(name, en, math);
	}
}

3、在main方法中定义一个打印机对象,和三个学生操作类线程,三个线程同时启动,代码如下:

public class Run {
	public static void main(String[] args) {
		Print print=new Print();
		
		StudentThread stu1=new StudentThread(print, "诸葛亮", 100, 100);
		StudentThread stu2=new StudentThread(print, "张飞", 10, 40);
		StudentThread stu3=new StudentThread(print, "刘备", 80, 90);
		
		stu1.start();
		stu2.start();
		stu3.start();
		
	}

}

运行上面的代码,控制台打印如下:

attcontent/f3f222bb-28b5-441d-a245-ed98f6fc75f5.png

可以看到所有人的成绩都错乱了,根据不知道那个成绩是那一个学生的。要防止这种情况非常简单,只需要在打印类中的打印方法前面加上synchronized关键字实现同步即可,修改打印机类如下:

public class Print {
	
	public synchronized  void p(String name,int en,int math){
		System.out.print("姓名:"+name+":");
		System.out.println("数学成绩:"+math+",英语成绩:"+en);
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

再次运行代码,结果如下:

attcontent/17aaf28e-8549-46e9-a404-024b2f9ac742.png