Java 多线程学习笔记十九(三大不安全案例)

内容来自B站【狂神说Java】多线程详解

一、不安全的买票

代码演示

package org.example.thread;

/**
 * 不安全的买票
 * @author 86153
 *
 */
public class UnsafeBuyTicket {

	public static void main(String[] args) {
		BuyTicket buyTicket = new BuyTicket();
		new Thread(buyTicket, "墨倾池").start();
		new Thread(buyTicket, "砚寒清").start();
		new Thread(buyTicket, "默仓离").start();
	}
	
}

class BuyTicket implements Runnable {

	// 票
	private int ticketNums = 10;
	// 外部停止方式
	boolean flag = true;
	
	@Override
	public void run() {
		// 买票
		while (flag) {
			try {
				buy();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	private void buy() throws InterruptedException {
		// 判断是否邮票
		if (ticketNums <= 0) {
			flag = false;
			return;
		}
		// 模拟延时
		Thread.sleep(100);
		// 买票
		System.out.println(Thread.currentThread().getName() + "买到了第--> " + (ticketNums--) + " 张票");
	}
	
}

分析

Q:-1是如何出现的?
A:每个线程都有自己的工作内存,当票数是1时,线程看到的都是1,都将1拷贝到了自己的工作内存中,进行买票操作后一共减了三次,出现了0和-1。

二、银行取钱

代码演示

package org.example.thread.sync;

/**
 * 不安全的取钱
 * 两个人取同一个账户的钱
 * @author 86153
 *
 */
public class UnsafeBank {
	
	public static void main(String[] args) {
		// 账户
		Account account = new Account(100, "结婚基金");
		Drawing you = new Drawing(account, 50, "你");
		Drawing girlFriend = new Drawing(account, 100, "girlFriend");
		
		you.start();
		girlFriend.start();
	}

}

/**
 * 账户
 * @author 86153
 *
 */
class Account {
	
	// 余额
	int money;
	// 卡名
	String name;
	
	public Account(int money, String name) {
		super();
		this.money = money;
		this.name = name;
	}
	
}

/**
 * 银行,模拟取款
 * @author 86153
 *
 */
class Drawing extends Thread {
	
	// 账户
	Account account;
	// 取了多少钱
	int drawingMoney;
	// 现在手里有多少钱
	int nowMoney;
	
	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) {
			System.out.println(Thread.currentThread().getName() + "钱不够,取不了");
			return;
		}
		
		// sleep可以放大问题的发生性
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		// 卡内余额 = 余额 - 你取的钱
		account.money = account.money - drawingMoney;
		// 你手里的钱
		nowMoney = nowMoney + drawingMoney;
		System.out.println(account.name + "余额为:" + account.money);
		// Thread.currentThread().getName() == this.getName()
		System.out.println(this.getName() + "手里的钱为:" + nowMoney);
	}
	
}


三、List

代码演示

package org.example.thread.sync;

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

/**
 * 线程不安全的集合
 * @author 86153
 *
 */
public class UnsafeList {
	
	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		for (int i = 0; i < 10000; i++) {
			new Thread(() -> {
				list.add(Thread.currentThread().getName());
			}).start();
		}
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(list.size());
	}

}

输出

9998
posted @ 2022-01-01 11:19  君子键  阅读(29)  评论(0)    收藏  举报