多线程_并发_非同步_三大经典案例

线程同步(synchronized):是指在一个多线程的环境下,我们要保证数据的准确性和安全性,同时还要提高它的性能。

在这里插入图片描述

package com.sxt.syn;
/**
 * 线程不安全: 数据有负数、相同
 * 
 * @author 
 *
 */
public class UnsafeTest01 {

	public static void main(String[] args) {
		//一份资源
		UnsafeWeb12306 web =new UnsafeWeb12306();
		//多个代理
		new Thread(web,"码畜").start();
		new Thread(web,"码农").start();
		new Thread(web,"码蟥").start();;
	}
}

class UnsafeWeb12306 implements Runnable{
	//票数
	private int ticketNums =10;
	private boolean flag = true;
	@Override
	public void run() {
		while(flag) {
			test();
		}
	}	
	public void test() {
		if(ticketNums<0) {
			flag = false;
			return ;
		}
		//模拟延时
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);
	}
}

模拟12306抢票
负数的出现:假设最后一张票是1,现在A、B、C都来抢票,假设B进来了,A也进来了,C也进来了,假设B优先进来,Thread.sleep(200)等待(抱着资源睡觉),A跟C都在等待,假设B先获得时间片把这张票拿走了,此时C醒来了,只能拿0,A也醒来了只能拿-1。这是临界值的概念,就是最后一张票你没有控制,线程不安全。

相同票的出现:开辟多线程,线程会有自己的工作空间,现在有线程A、线程B、线程C,它们的工作空间和主存进行交互。假设主存中现在有PickNums=10,正常情况应该是线程A将10拷贝过来,并减个1,再覆盖回主存,此时主存的PickNums=9。出现相同票问题是因为线程B、线程C有可能在线程A减去1再覆盖回主存之前,将主存中的10也拷贝了过去。【主要的问题存在于工作内存和主内存在拷贝的时候,即获取值的时候不一致,没有等到主内存更新完以后再来拷贝】

package com.sxt.syn;
/**
 * 线程不安全:取钱
 * 
 * @author 
 *
 */
public class UnsafeTest02 {
	public static void main(String[] args) {
		//账户
		Account account =new Account(100,"结婚礼金");
		Drawing you = new Drawing(account,80,"可悲的你");
		Drawing wife = new Drawing(account,90,"happy的她");
		you.start();
		wife.start();
	}
}
//模拟取款
class Drawing extends Thread{
	Account account ; //取钱的账户
	int drawingMoney ;//取的钱数
	int packetTotal ; //口袋的总数	
	
	public Drawing(Account account, int drawingMoney,String name) {
		super(name);
		this.account = account;
		this.drawingMoney = drawingMoney;
	}

	@Override
	public void run() {
		if(account.money -drawingMoney<0) {
			return;
		}
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		account.money -=drawingMoney;
		packetTotal +=drawingMoney;
		System.out.println(this.getName()+"-->账户余额为:"+account.money);
		System.out.println(this.getName()+"-->口袋的钱为:"+packetTotal);
	}
} 


package com.sxt.syn;

import java.util.ArrayList;
import java.util.List;

/**
 * 线程不安全:操作容器
 * 
 * @author 
 */
public class UnsafeTest03 {
	public static void main(String[] args) throws InterruptedException {
		List<String> list = new ArrayList<String>();
		for(int i=0;i<10000;i++) {
			new Thread(()->{
				list.add(Thread.currentThread().getName());
			}) .start();
		}
		System.out.println(list.size());
	}
}

不是所有的情况下都要保证线程安全,一般来说我们对数据存在“改”的行为我们就需要控制它保证线程安全,如果只是对数据进行“读”的行为,也就是只拷贝,那就没关系。
存在又“改”又“读”,也需要保证线程安全。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值