线程安全隐患---同步代码块

1.线程安全
多线程同时操作一个共享数据,往往会出现安全问题
在这里插入图片描述
例如这里:有三个线程,当ticket=1,t0线程抢到CPU资源,if判断结果为真,准备运行打印语句时,CPU资源突然被线程t1抢走了,此时ticket还没有进行(ticket–)操作,所以t1的if判断结果结尾也是真,此时准备运行打印语句时,CPU资源突然被又线程t3抢走了,此时ticket依旧没有进行(ticket–)操作,所以这里if判断结果依旧为真,这里t0和t1都陷入了临时阻塞的状态,当t0又抢到CPU的资源,(ticket–)结果打印出来就是(0),然后当t1又抢到CPU的资源时,(ticket–)结果打印出来就是(-1)。这样就出现了安全隐患。

例:一个售票系统,可以通过网上同时多人买票。

package cn.itcast.demo01;
//并发操作,同时针对一个数据源实行并发操作
public class Tickets01 implements Runnable{
	private int tickets = 10;

	public void run() {
		while(true){
		if(tickets > 0){
			try {
				//为了能更容易地看到这个隐患,让线程在这故意休眠10ms
				Thread.sleep(10L);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"...出售了第"+(tickets--)+"张");
		}
	}
	}
}

package cn.itcast.demo01;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//并发操作
public class ThreadDemo01 {
	public static void main(String[] args) {
		Runnable r = new Tickets01();
		// 创建线程池
		ExecutorService es = Executors.newFixedThreadPool(2);
		es.submit(r);
		es.submit(r);
		es.shutdown();
	}
}

出现安全隐患的结果如图:
在这里插入图片描述
结果这里打印了不应该存在的0;

2.同步技术
java提供了一种技术:同步技术,用来解决线程的安全问题。
下面简单写一下同步代码块的格式:
sychronized(任意对象){
线程共享数据;
}
任意对象,这里的对象又称同步锁,对象监视器。
注意:这里不能写匿名对象,通常写 Object object= new Object(),用obj作为同步代码块的锁。

3.同步代码块的执行原理
线程遇到同步代码块,线程首先会判断有没有同步锁
有–>则获取锁并进入到同步代码块中,等代码块中的程序执行完毕,出代码块,并归还所。
无–>则无法进入同步代码块,被挡在代码块的外面。
好处:代码简洁,节约内存。

下面是加了同步代码块的代码,mian函数还是那样。

package cn.itcast.demo01;
//并发操作,同时针对一个数据源实行并发操作
public class Tickets01 implements Runnable{
	private int tickets = 10;
	//同步代码块的锁
	Object obj = new Object();
	public void run() {
		while(true){
			synchronized (obj) {
				if(tickets > 0){
					try {
						//为了能更容易地看到这个隐患,让线程在这故意休眠10ms
						Thread.sleep(10L);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"...出售了第"+(tickets--)+"张");
				}
			}
	}
	}
}

这里还可以将共享数据抽取出来,写成一个方法,在方法的声明中加入sychronized
例:public sychronized void pay(){ }//这里的同步对象锁就是this了。

package cn.itcast.demo01;

//并发操作,同时针对一个数据源实行并发操作
public class Tickets01 implements Runnable {
	private int tickets = 10;

	public void run() {
		while (true) {
			pay();
		}
	}

	public synchronized void pay() {
			if (tickets > 0) {
				try {
					// 为了能更容易地看到这个隐患,让线程在这故意休眠10ms
					Thread.sleep(10L);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "...出售了第"
						+ (tickets--) + "张");
		}
	}
}


问:
(1)同步方法有锁吗?
答:有,锁就是本类对象引用this
(2)如果同步方法是静态的,同步还有锁吗?
答:有,锁就是本类类名.class,不是this。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值