线程同步--三大线程不安全例子

线程同步--三大线程不安全例子

概念

线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该地址进行操作,而其他线程又处于等待状态

锁机制

由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入synchronized, 当一个线程获得其他对象的排它锁,独占资源,其他线程必须等待,使用后释放即可,存在以下问题

  • 一个线程持有锁会导致其他所有需要此锁的线程挂起
  • 在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题
  • 如果一个优先级高的线程等待一个优先级低的线程释放锁 会导致优先级倒置,引起性能问题

线程不安全的三个小例子

1.买票

package com.example.multi_thread;

public class UnsafeBuyTicket {
    public static void main(String[] args) {
        Ticket ticket = new Ticket(10);
        new Thread(ticket, "我").start();
        new Thread(ticket, "你").start();
        new Thread(ticket, "黄牛").start();

    }
}

class Ticket implements Runnable {

    private int num;

    boolean flag = true;

    public Ticket(int num) {
        this.num = num;
    }

    @Override
    public void run() {
        while (flag) {
            buy();

        }

    }

    private void buy() {
        if (num <= 0) {
            flag = false;
            return;
        }
        System.out.println(Thread.currentThread().getName() + "拿到" + num--);
    }


}

输出 出现-1

我拿到10
黄牛拿到8
你拿到9
黄牛拿到6
我拿到7
黄牛拿到4
你拿到5
黄牛拿到2
我拿到3
黄牛拿到0
你拿到1
我拿到-1

2.取钱

package com.example.multi_thread;

import lombok.SneakyThrows;

public class DrawingMoney {
    public static void main(String[] args) {
        Account account = new Account(100, "my");

        Drawing drawing1 = new Drawing(account, 50, "我");
        Drawing drawing2 = new Drawing(account, 100, "boyFriend");

        drawing1.start();
        drawing2.start();
    }
}

// 账户
class Account {
    int balance; // 余额
    String name; // 账户名称

    public Account(int balance, String name) {
        this.balance = balance;
        this.name = name;
    }
}

class Drawing extends Thread {

    private Account account;
    private int drawingMoney;
    private int nowMoney;//

    public Drawing(Account account, int drawingMoney, String name) {
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    @SneakyThrows
    @Override
    public void run() {
        if (account.balance - drawingMoney < 0) {
            System.out.println(currentThread().getName() + "余额不足");
            return;
        }
        // 模拟网络延时
        Thread.sleep(3000);
        account.balance -= drawingMoney;
        nowMoney += drawingMoney;
        System.out.println(account.name + "账户余额" + account.balance);
        System.out.println(currentThread().getName() + "手里的钱" + nowMoney);

    }
}

输出:出现余额为负数

my账户余额-50
我手里的钱50
my账户余额-50
boyFriend手里的钱100

3.ArrayList

package com.example.multi_thread;

import java.util.ArrayList;

public class TestArrayList {
    public static void main(String[] args) {
        ArrayList<Object> objects = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(() -> {
                objects.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(objects.size());
    }
}

输出:出现多条数据修改同一个地址

9999
posted @ 2021-11-12 20:48  Oh,mydream!  阅读(112)  评论(0编辑  收藏  举报