synchronized浅析

来源:互联网 发布:泰格软件安装 编辑:程序博客网 时间:2024/06/13 13:50

   引言

   这篇博客算是我在CSDN发表的第一篇博客,小生无名,没必要介绍自己,那么就此开始CSDN生涯,开始这篇博客吧


一、synchronized是什么

       它是java的一个关键字。

二、synchronized的作用

       两个字,处理并发问题。

三、何谓并发?

      我以一个java例子来说明。

      需求:一包面包10片,蒙在黑布里,有两个人A和B拿面包,要求每人都能拿到面包,拿完后给出"没有面包了"的打印信息


start coding

      A和B我们看做两个线程,那么新建一个类:MyThread继承Thread;

      一包20片的面包为共享资源,这里我们只操作数量:static int count =10;

      我们要知道每一步操作的人是谁,那么要在构造方法里传入操作者的名称;

      基本代码如下:

public class MyThread extends Thread{static int count =10;public  MyThread(String name) {this.setName(name);}@Overridepublic void run() {super.run();}}

      接下来,开始进行run方法里的编码,很简单,A或B拿了面包后,将数量减一,数量为0时,退出操作,为了让A和B一直拿,写一个死循环while(true)。

    run方法的代码如下:

while(true){if(count>0){System.out.println(getName()+"拿了一片面包,现在还剩"+(count-1)+"片");count--;}else{System.out.println("没有面包了");break;}}

接着开始测试,在main方法里这样写就OK了:

  MyThread thread1 = new MyThread("A");MyThread thread2 = new MyThread("B");thread1.start();thread2.start();

打印信息如下:


看到问题了没?A秒拿了好几次面包,B来拿了一个的时候,剩余数量竟然还是9!这显然是不正确的,出现这个问题的原因是因为面包被黑布蒙着,A和B第一次拿面包的时候,都以为自己拿的是第一片,也就是A和B的代码同时运行到

System.out.println(getName()+"拿了一片面包,现在还剩"+(count-1)+"片");
这一段,这时候,对A和B来说,count都是10,所以一起报出:剩余数量为9,这就是所谓并发问题。

怎么解决呢?用synchronized。

synchronized对于本例来说,可以这样理解:

把面包锁在一间屋子里,A和B的其中一个最先赶到屋子前,拿起地上的钥匙打开房门,然后进去,接着反手把门关上,一个人愉快的拿面包,这个时候,另外一个人来到门前,唉声叹气,只能等待前者拿完出来,因为他没有钥匙。

而前者拿完面包,开门出来,把钥匙扔地上,转身离去,这时候等待的人飞速拿起钥匙,然后就是重复以上操作了。

这个时候,A和B有充足的时间看到底还剩几片,然后报出信息。

那么怎么用synchronized呢?

1、修饰方法体

2、修饰代码块


修饰方法体

  synchronized修饰方法的话,有两种不一样的地方,一种是加static,一种是不加static。

    加static则synchronized的锁是这个类.class,不加static则锁是这个类的对象。

  也可以这样理解:加了static的方法不受子类约束,也就是唯一的方法,把这个方法锁起来,那子类们都去排队去吧!

    以本例来说,加static则意味着钥匙只有一把,而且synchronized修饰方法体,那么A或B拿到这把钥匙后,就会进房间把面包拿完,然后才会出来,这样另外一个人一直在门外,等待前者把面包全部拿完,好气啊!不加static呢,则意味着钥匙可以有无数把,因为一个类的对象可以是无数个,那么A和B每个人都持有一把钥匙,随意进出,那么这样就不能处理上面的并发问题。所以想要解决本例问题,只能加static。

代码改为如下:

public class MyThread extends Thread{static int count =10;public  MyThread(String name) {setName(name);}@Overridepublic  void run() {super.run();System.out.println(getName()+"要开始拿面包了!");action(getName());}private static synchronized void action(String name){while(true){if(count>0){System.out.println(name+"拿了一片面包,现在还剩"+(count-1)+"片");count--;}else{System.out.println("没有面包了");break;}}}}


打印信息:

可以清晰的看出B的绝望。。。当他进去的时候,已经没有面包啦~

修饰代码块

上面的方法显然不符合我们要求,我们要求每个人都能拿到面包!那么看看修饰代码块吧!

修饰代码块的使用方法和上面有所不同,修饰代码块需要给synchronized指定一个参数,也就是指定一个锁的类型,可以是金锁,也可以是银锁~

那么代码改为:

public class MyThread extends Thread{static int count =10;public  MyThread(String name) {setName(name);}@Overridepublic  void run() {super.run();           while(true){           synchronized (MyThread.class) {         if(count>0){    System.out.println(getName()+"拿了一片面包,现在还剩"+(count-1)+"片");    count--;   }else{System.out.println("没有面包了");break;}   }       }     }}
打印结果:


完美达成要求~

B说:我只拿了两个面包,我有小情绪了!谁叫你速度没A快呢?不过这也是随机的,可能下次拿面包比赛,你拿的就会多一点啦~


1 0
原创粉丝点击