-
并发:同一个对象被多个线程同时操作
-
处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象,这个时候就需要线程同步。
-
线程同步实际上就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程再使用
-
形成条件:队列+锁(synchronized)
例1:线程不安全买票
//有负数出现 public class UnsafeBuyTicket { public static void main(String[] args) { BuyTicket station = new BuyTicket(); new Thread(station,"抢票的你").start(); new Thread(station,"开挂的我").start(); new Thread(station,"黄牛党").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--); } } /* 抢票的你拿到了10 开挂的我拿到了10 黄牛党拿到了9 开挂的我拿到了8 抢票的你拿到了7 黄牛党拿到了6 开挂的我拿到了5 黄牛党拿到了3 抢票的你拿到了4 抢票的你拿到了2 开挂的我拿到了1 黄牛党拿到了0 抢票的你拿到了-1 */
例2:线程安全买票
... //synchronized同步方法,锁的是this private synchronized void buy() throws InterruptedException { ... } ...
例3:线程不安全取钱
public class UnsafeBank{ public static void main(String[] args) { Account account = new Account(100,"存款"); Drawing you = new Drawing(account,50,"you"); Drawing i = new Drawing(account,100,"1"); you.start(); i.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; } //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); } } /* 存款余额为:-50 i手上的钱:100 存款余额为:-50 you手上的钱:50 */
例4:线程安全取钱
... //synchronized默认锁的是this. @Override public void run(){ //锁的对象就是变化的量 synchronized(account){ 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); } } ...
例5:线程不安全的集合
//结果并不是10000,说明有元素被替换,线程不安全 public class UnsafeList{ public static void main(String[] args){ List<String> list = new ArrayList<String>(); 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()); //9997 } }
例6:线程不安全的集合变为安全
... new Thread(()->{ synchronized(list){ list.add(Thread.currentThread().getName()); } }).start(); ...
线程同步
最新推荐文章于 2024-10-01 18:51:18 发布
本文通过示例介绍了Java中并发编程时可能出现的问题,如线程不安全的买票和取钱场景,展示了线程不安全的集合操作。通过引入`synchronized`关键字实现线程安全,确保了在多线程环境下对象状态的一致性。同时,讨论了线程同步的重要性以及如何通过锁机制避免数据竞争,以保证程序的正确运行。
摘要由CSDN通过智能技术生成