线程同步发生在多个线程操作同一个资源时
并发:同一个对象被多个线程同时操作(可参考前面买火车票和龟兔赛跑的例子)
处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象,此时就需要线程同步,线程同步是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面的线程使用完毕,下一个线程再使用
队列和锁(线程同步的形成条件)
形象一点,下面的文字可以结合生活中公共厕所来理解
由于同一个进程的多个线程共享同一块存储空间(公共厕所),在带来方便的同时,也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入了锁机制synchronized,当一个线程获得对象的排他锁,独占资源,其他线程必须等待,使用后释放锁即可(用时关门,用完开门),存在以下问题:
①一个线程持有锁会导致其他有需要此锁的线程挂起(等待)
②在多线程竞争下,加锁,释放锁会导致较多的上下文切换和调度延时,引起性能问题(进进出出)
③如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题(使用时间的长短)
线程同步的实现
①在方法前添加synchronized关键字,让该方法成为同步方法,锁的是this(如果将一个很复杂的方法变为同步方法,会影响效率)
②同步块:synchronized(共享资源作为对象){}
1 public class Bank { 2 public static void main(String[] args) { 3 Account account = new Account(500, "结婚基金"); 4 Get you = new Get(account, 300, "你"); 5 Get youGf = new Get(account, 500, "你女朋友"); 6 you.start(); 7 youGf.start(); 8 } 9 } 10 11 //账户 12 class Account { 13 int money; 14 String cdName;//卡号 15 16 public Account(int money, String name) { 17 this.money = money; 18 cdName = name; 19 } 20 } 21 22 //模拟银行取钱 23 class Get extends Thread { 24 Account account; 25 int getMoney;//取多少钱 26 String Name;//取钱的是人 27 28 public Get(Account account, int getMoney, String Name) { 29 this.account = account; 30 this.getMoney = getMoney; 31 this.Name = Name; 32 } 33 34 @Override 35 public void run() { 36 //同步块 37 synchronized (account) { 38 if (account.money - getMoney < 0) { 39 System.out.println(Name + "取的时候,余额不足"); 40 return; 41 } 42 43 try { 44 Thread.sleep(1000); 45 } catch (InterruptedException e) { 46 e.printStackTrace(); 47 } 48 //余额 49 account.money = account.money - getMoney; 50 51 System.out.println(Name + "取后," + "卡里的钱为" + account.money); 52 } 53 54 } 55 }