多线程执行,为啥明明已经加了synchronized了,还是出现每次结果都不一样呢?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程执行,为啥明明已经加了synchronized了,还是出现每次结果都不一样呢?相关的知识,希望对你有一定的参考价值。
public class Test
private int a = 0;
public static void main(String[] args)
Test test = new Test();
for (int i = 0; i <= 10; i++)
new Thread(new Runnable()
@Override
public void run()
test.setA(test.getA() + 1);
).start();
System.out.println(test.getA());
public int getA()
return a;
public synchronized void setA(int a)
this.a = a;
如果我把synchronide 放到run方法里则执行正确? 为什么呢? 锁不是当前对象吗? 只有一个test对象啊?
synchronized(this)是对这里面的内容进行加锁的
多线程:(synchronized方法synchronized块JUC)
1、synchronized关键字的同步方法
包括两种用法:synchronized方法和synchronized块,synchronized控制对象的访问,每一个对相对应一把锁,每一个synchronized方法都必须获得带哦用该方法对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的对象才能够得到这个锁,继续执行
缺点:若将一个大的方法申明为synchronized将会影响效率,方法里面需要修改的内容才需要锁,锁太多的话会造成资源的浪费
(1)在添加关键字以前存在线程安全问题:
zhao拿到了第10张票
zhai拿到了第9张票
zhang拿到了第8张票
zhao拿到了第7张票
zhai拿到了第6张票
zhang拿到了第5张票
zhao拿到了第4张票
zhai拿到了第3张票
zhang拿到了第2张票
zhao拿到了第1张票
zhai拿到了第0张票
zhang拿到了第-1张票
(2)添加关键字,为方法加锁:
public class BuyTickets implements Runnable { private int ticketNum=10; boolean flag=true; @Override public void run() { while (flag){ buy(); } } //synchronized实现同步方法 private synchronized void buy(){ if(ticketNum<=0){ flag=false; return; } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNum--+"张票"); } }
测试类:
public class Test { public static void main(String[] args) { BuyTickets buyTickets=new BuyTickets(); new Thread(buyTickets,"zhai").start(); new Thread(buyTickets,"zhang").start(); new Thread(buyTickets,"zhao").start(); } }
测试结果:
zhai拿到了第10张票
zhao拿到了第9张票
zhao拿到了第8张票
zhang拿到了第7张票
zhao拿到了第6张票
zhai拿到了第5张票
zhao拿到了第4张票
zhao拿到了第3张票
zhang拿到了第2张票
zhao拿到了第1张票
没有出现票为负数的情况,没有出现票的编号重复的情况
2、synchronized同步块
可以监视任何对象,但是推荐使用共享资源作为同步监视器,同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this,就是对象本身
第1个线程访问,锁定同步监视器,执行其中的代码
第2个线程访问,发现同步监视器被锁定,无法访问
第1个线程访问完毕,解锁同步监视器
第2个线程访问,发现同步监视器没有锁,然后锁定并访问
(1)对变化的对象加锁:
public class BankTest extends Thread{ Account account; int drawingMoney;//取出的金额 int nowMoney;//现金 public BankTest(Account account,int drawingMoney,String name){ super(name); this.account=account; this.drawingMoney=drawingMoney; } public void run(){ synchronized (account){ //判断是否有余额 if(account.money-drawingMoney<0){ System.out.println("余额不足"); return; } try { Thread.sleep(1000);//放大问题的发生性 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("余额:"+account.money); account.money=account.money-drawingMoney;//余额 nowMoney=nowMoney+drawingMoney; System.out.println(this.getName()+"现金:"+nowMoney); } }
public class Account { int money;//余额 String name;//名字 public Account(int money, String name) { this.money = money; this.name = name; } }
public class Test { public static void main(String[] args) { Account account=new Account(1000,"工资"); BankTest bankTest1=new BankTest(account,150,"tom"); BankTest bankTest2=new BankTest(account,200,"jack"); bankTest1.start(); bankTest2.start(); } }
余额:1000 tom现金:150 余额:850 jack现金:200
(2)为集合加锁:
public class UnSafeList { public static void main(String[] args) { List<String> list=new ArrayList<String>(); for(int i=0;i<10000;i++){ new Thread(()->{ synchronized (list){ list.add(Thread.currentThread().getName()); } }).start(); } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); } }
3、JUC
测试JUC安全类型的集合
public class UnSafeList { public static void main(String[] args) { CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<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()); } }
10000
以上是关于多线程执行,为啥明明已经加了synchronized了,还是出现每次结果都不一样呢?的主要内容,如果未能解决你的问题,请参考以下文章