线程同步

一、什么是线程的同步

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) {
        	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,80);
		
		stu1.start();
		stu2.start();
		stu3.start();
	}
}

实验结果:
在这里插入图片描述
可以看到所有人的成绩都错乱了,根据不知道那个成绩是那一个学生的。要防止这种情况非常简单,只需要在打印类中的打印方法前面加上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) {
        	e.printStackTrace();
        }
	}
}

实验结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值