本文共 3130 字,大约阅读时间需要 10 分钟。
并发与锁机制
在并发编程中,多个线程同时操作同一资源时,会出现访问冲突的问题。为了确保访问的正确性,Java引入了锁机制(synchronized),通过加锁和释放锁来控制资源的访问。然而,锁机制也伴随着一些问题:
抢票不安全
以下示例展示了线程不安全导致的数据紊乱。每个线程都试图从票盘中抢票,当票数为0时,线程停止运行。由于没有同步机制,多个线程可能在同一时间修改票数,导致票数出现负数。
public class UnsafeBuyTicket { public static void main(String[] args) { Myticket myticket = new Myticket(); new Thread(myticket, "用户1").start(); new Thread(myticket, "用户2").start(); new Thread(myticket, "用户3").start(); }}class Myticket implements Runnable { private int tickets = 10; boolean flag = true; @Override public void run() { while (flag) { try { buy(); } catch (InterruptedException e) { e.printStackTrace(); } } } private void buy() throws InterruptedException { while (flag) { if (tickets <= 0) { flag = false; return; } Thread.sleep(100); System.out.println(Thread.currentThread().getName() + "抢到了第" + tickets-- + "张票"); } }}
结果:抢票结果会出现负数,线程不安全。
同时取钱不安全
以下示例展示了线程不安全导致的账户余额问题。每个线程尝试从账户中取款,当账户余额不足时,线程停止运行。由于没有同步机制,多个线程可能在同一时间修改账户余额,导致余额出现负数。
public class UnsafaBank { public static void main(String[] args) { Account account = new Account(100, "卡内"); Drawing drawing01 = new Drawing(account, 50, "用户1"); Drawing drawing02 = new Drawing(account, 100, "用户2"); drawing01.start(); drawing02.start(); }}class Account { int money; String name; public Account(int money, String name) { this.money = money; this.name = name; }}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; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } account.money -= drawingmoney; nowmoney = nowmoney + drawingmoney; System.out.println(account.name + "余额为:" + account.money); System.out.println(Thread.currentThread().getName() + "取出" + nowmoney); }}
结果:线程不安全,两个线程同时对一个资源操作时,出现余额为负数。
线程不安全
List是Java中的一个常用集合类,用于存储和操作一系列的对象。ArrayList、LinkedList和Vector都是List的实现类。以下示例展示了线程不安全的影响:当多个线程同时尝试向列表添加元素时,可能会导致元素覆盖。
public class UnsafeList { public static void main(String[] args) { Listlist = 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()); }}
结果:由于多个线程同时将线程名加入列表,导致覆盖,列表没有达到10000个元素。
转载地址:http://nimg.baihongyu.com/