java synchronized关键字

synchronized关键字的作用是保证多线程操作的安全
简单说:多个线程公用一把锁时,就要一个一个来执行

1.不使用synchronized

class Fun{
      public void run(){
          for (int i = 0; i < 10; ++i)
          {
              System.out.println("Hello: " + i+"____"+Thread.currentThread().getName());
          }
      }
}
class MyThread extends Thread{
    Fun fun;
    public MyThread(Fun fun){
        this.fun = fun;
    }
    @Override
    public void run() {
        fun.run();
    }
}
测试运行
       Fun fun = new Fun();
        MyThread thread1 = new MyThread(fun);
        MyThread thread2 = new MyThread(fun);
        thread1.start();
        thread2.start();

结果:

11-13 15:43:53.238 791-918/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 0____Thread-2
11-13 15:43:53.238 791-926/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 0____Thread-3
11-13 15:43:53.238 791-918/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 1____Thread-2
11-13 15:43:53.238 791-926/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 1____Thread-3
11-13 15:43:53.238 791-918/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 2____Thread-2
11-13 15:43:53.238 791-918/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 3____Thread-2
11-13 15:43:53.238 791-918/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 4____Thread-2
11-13 15:43:53.238 791-918/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 5____Thread-2
11-13 15:43:53.238 791-918/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 6____Thread-2
11-13 15:43:53.238 791-918/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 7____Thread-2
11-13 15:43:53.238 791-918/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 8____Thread-2
11-13 15:43:53.238 791-918/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 9____Thread-2
11-13 15:43:53.239 791-926/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 2____Thread-3
11-13 15:43:53.239 791-926/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 3____Thread-3
11-13 15:43:53.239 791-926/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 4____Thread-3
11-13 15:43:53.239 791-926/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 5____Thread-3
11-13 15:43:53.239 791-926/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 6____Thread-3
11-13 15:43:53.239 791-926/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 7____Thread-3
11-13 15:43:53.239 791-926/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 8____Thread-3
11-13 15:43:53.239 791-926/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 9____Thread-3

从中可以看出,到底是哪个线程先运行时没有章法的,也就是不同步,哪个线程抢到了运行权哪个线程就运行.
如果使用了synchronized呢?

2.synchronized修饰普通方法

只需稍微修改下:
class Fun{
      public synchronized void run(){
          for (int i = 0; i < 10; ++i)
          {
              System.out.println("Hello: " + i+"____"+Thread.currentThread().getName());
          }
      }
}

结果:

11-13 15:45:26.288 3848-3881/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 0____Thread-2
11-13 15:45:26.288 3848-3881/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 1____Thread-2
11-13 15:45:26.288 3848-3881/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 2____Thread-2
11-13 15:45:26.288 3848-3881/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 3____Thread-2
11-13 15:45:26.288 3848-3881/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 4____Thread-2
11-13 15:45:26.288 3848-3881/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 5____Thread-2
11-13 15:45:26.288 3848-3881/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 6____Thread-2
11-13 15:45:26.288 3848-3881/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 7____Thread-2
11-13 15:45:26.288 3848-3881/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 8____Thread-2
11-13 15:45:26.288 3848-3881/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 9____Thread-2
11-13 15:45:26.288 3848-3882/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 0____Thread-3
11-13 15:45:26.288 3848-3882/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 1____Thread-3
11-13 15:45:26.288 3848-3882/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 2____Thread-3
11-13 15:45:26.288 3848-3882/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 3____Thread-3
11-13 15:45:26.288 3848-3882/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 4____Thread-3
11-13 15:45:26.288 3848-3882/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 5____Thread-3
11-13 15:45:26.288 3848-3882/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 6____Thread-3
11-13 15:45:26.288 3848-3882/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 7____Thread-3
11-13 15:45:26.289 3848-3882/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 8____Thread-3
11-13 15:45:26.289 3848-3882/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 9____Thread-3

从中可以看出,thread2执行完fun.run()方法之后,thread3才会执行,这说明thread2在执行的时候获取了锁,直到执行完之后才把锁释放,这就保证了线程安全

但是,如果我定义两个Fun对象呢,比如这样

Fun fun1 = new Fun();
        Fun fun2 = new Fun();
        MyThread thread1 = new MyThread(fun1);
        MyThread thread2 = new MyThread(fun2);
        thread1.start();
        thread2.start();

结果如下:

11-13 15:53:56.401 11201-11233/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 0____Thread-2
11-13 15:53:56.401 11201-11234/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 0____Thread-3
11-13 15:53:56.401 11201-11233/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 1____Thread-2
11-13 15:53:56.401 11201-11233/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 2____Thread-2
11-13 15:53:56.401 11201-11234/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 1____Thread-3
11-13 15:53:56.401 11201-11233/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 3____Thread-2
11-13 15:53:56.401 11201-11234/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 2____Thread-3
11-13 15:53:56.401 11201-11233/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 4____Thread-2
11-13 15:53:56.401 11201-11234/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 3____Thread-3
11-13 15:53:56.401 11201-11233/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 5____Thread-2
11-13 15:53:56.401 11201-11234/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 4____Thread-3
11-13 15:53:56.401 11201-11233/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 6____Thread-2
11-13 15:53:56.401 11201-11234/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 5____Thread-3
11-13 15:53:56.401 11201-11233/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 7____Thread-2
11-13 15:53:56.401 11201-11234/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 6____Thread-3
11-13 15:53:56.401 11201-11233/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 8____Thread-2
11-13 15:53:56.401 11201-11234/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 7____Thread-3
11-13 15:53:56.401 11201-11233/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 9____Thread-2
11-13 15:53:56.401 11201-11234/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 8____Thread-3
11-13 15:53:56.401 11201-11234/com.dgtech.sss.synchronizeddemo I/System.out: Hello: 9____Thread-3

结果说明,线程又不同步了
为什么呢?
因为synchronized修饰的普通方法的的锁是这个类的对象,在示例中我们定义了两个对象,也就是每个thread用的锁不是一个,每个thread都有自己的锁,这跟上面例子不同的地方就是,上面例子只有一把锁,这个有两把锁
接着往下看:

3.synchronized修饰static方法

class Fun{
      public static synchronized void run(){
          for (int i = 0; i < 10; ++i)
          {
              System.out.println("Hello: " + i+"____"+Thread.currentThread().getName());
          }
      }
}
class MyThread extends Thread{
    Fun fun;
    public MyThread(Fun fun){
        this.fun = fun;
    }
    @Override
    public void run() {
        Fun.run();
    }
}
调用情况:
 Fun fun1 = new Fun();
        Fun fun2 = new Fun();
        MyThread thread1 = new MyThread(fun1);
        MyThread thread2 = new MyThread(fun2);
        thread1.start();
        thread2.start();

结果:

11-13 16:05:00.805 19091-19106/? I/System.out: Hello: 0____Thread-2
11-13 16:05:00.805 19091-19106/? I/System.out: Hello: 1____Thread-2
11-13 16:05:00.805 19091-19106/? I/System.out: Hello: 2____Thread-2
11-13 16:05:00.805 19091-19106/? I/System.out: Hello: 3____Thread-2
11-13 16:05:00.805 19091-19106/? I/System.out: Hello: 4____Thread-2
11-13 16:05:00.805 19091-19106/? I/System.out: Hello: 5____Thread-2
11-13 16:05:00.805 19091-19106/? I/System.out: Hello: 6____Thread-2
11-13 16:05:00.805 19091-19106/? I/System.out: Hello: 7____Thread-2
11-13 16:05:00.805 19091-19106/? I/System.out: Hello: 8____Thread-2
11-13 16:05:00.805 19091-19106/? I/System.out: Hello: 9____Thread-2
11-13 16:05:00.805 19091-19107/? I/System.out: Hello: 0____Thread-3
11-13 16:05:00.805 19091-19107/? I/System.out: Hello: 1____Thread-3
11-13 16:05:00.805 19091-19107/? I/System.out: Hello: 2____Thread-3
11-13 16:05:00.805 19091-19107/? I/System.out: Hello: 3____Thread-3
11-13 16:05:00.805 19091-19107/? I/System.out: Hello: 4____Thread-3
11-13 16:05:00.805 19091-19107/? I/System.out: Hello: 5____Thread-3
11-13 16:05:00.805 19091-19107/? I/System.out: Hello: 6____Thread-3
11-13 16:05:00.805 19091-19107/? I/System.out: Hello: 7____Thread-3
11-13 16:05:00.805 19091-19107/? I/System.out: Hello: 8____Thread-3
11-13 16:05:00.805 19091-19107/? I/System.out: Hello: 9____Thread-3

结果是,又同步了.
为什么呢?
因为静态方法属于这个类,synchronized修饰的静态方法的锁是这个类,因为class只有一个,所以锁只有一把,因此就会同步.
既然synchronized修饰的静态方法的锁是这个class,也就是说当这个锁被占有的时候,这个类中的其他需要这个class当锁的方法一样得等到锁才能执行,下面看下例子来说明:

class Fun{
      public static synchronized void run(){
          for (int i = 0; i < 10; ++i)
          {
              System.out.println("Hello: " + i+"____"+Thread.currentThread().getName());
          }
      }
    public  static synchronized void run2(){
        for (int i = 0; i < 10; ++i)
        {
            System.out.println("Hello: " + i+"____"+Thread.currentThread().getName());
        }
    }
}
class MyThread extends Thread{
    Fun fun;
    public MyThread(Fun fun){
        this.fun = fun;
    }
    @Override
    public void run() {
        Fun.run();
    }
}
class MyThread2 extends Thread{
    Fun fun;
    public MyThread2(Fun fun){
        this.fun = fun;
    }
    @Override
    public void run() {
        Fun.run2();
    }
}
执行情况:
Fun fun1 = new Fun();
        Fun fun2 = new Fun();
        MyThread thread1 = new MyThread(fun1);
        MyThread2 thread2 = new MyThread2(fun2);
        thread1.start();
        thread2.start();

结果:

11-13 16:13:32.778 24600-24618/? I/System.out: Hello: 0____Thread-2
11-13 16:13:32.778 24600-24618/? I/System.out: Hello: 1____Thread-2
11-13 16:13:32.778 24600-24618/? I/System.out: Hello: 2____Thread-2
11-13 16:13:32.778 24600-24618/? I/System.out: Hello: 3____Thread-2
11-13 16:13:32.778 24600-24618/? I/System.out: Hello: 4____Thread-2
11-13 16:13:32.778 24600-24618/? I/System.out: Hello: 5____Thread-2
11-13 16:13:32.778 24600-24618/? I/System.out: Hello: 6____Thread-2
11-13 16:13:32.778 24600-24618/? I/System.out: Hello: 7____Thread-2
11-13 16:13:32.778 24600-24618/? I/System.out: Hello: 8____Thread-2
11-13 16:13:32.778 24600-24618/? I/System.out: Hello: 9____Thread-2
11-13 16:13:32.779 24600-24619/? I/System.out: Hello: 0____Thread-3
11-13 16:13:32.779 24600-24619/? I/System.out: Hello: 1____Thread-3
11-13 16:13:32.779 24600-24619/? I/System.out: Hello: 2____Thread-3
11-13 16:13:32.779 24600-24619/? I/System.out: Hello: 3____Thread-3
11-13 16:13:32.779 24600-24619/? I/System.out: Hello: 4____Thread-3
11-13 16:13:32.779 24600-24619/? I/System.out: Hello: 5____Thread-3
11-13 16:13:32.779 24600-24619/? I/System.out: Hello: 6____Thread-3
11-13 16:13:32.779 24600-24619/? I/System.out: Hello: 7____Thread-3
11-13 16:13:32.779 24600-24619/? I/System.out: Hello: 8____Thread-3
11-13 16:13:32.779 24600-24619/? I/System.out: Hello: 9____Thread-3

这两个thread运行的静态方法都需要这个Fun.class当作锁,因此执行是一个接着一个执行的
下面对这个例子稍微修改下

class Fun{
      public static synchronized void run(){
          for (int i = 0; i < 10; ++i)
          {
              System.out.println("Hello: " + i+"____"+Thread.currentThread().getName());
          }
      }
    public  synchronized void run2(){
        for (int i = 0; i < 10; ++i)
        {
            System.out.println("Hello: " + i+"____"+Thread.currentThread().getName());
        }
    }
}
class MyThread extends Thread{
    Fun fun;
    public MyThread(Fun fun){
        this.fun = fun;
    }
    @Override
    public void run() {
        Fun.run();
    }
}
class MyThread2 extends Thread{
    Fun fun;
    public MyThread2(Fun fun){
        this.fun = fun;
    }
    @Override
    public void run() {
        fun.run2();
    }
}

修改的关键一点:Fun中的run2()方法不是静态的
结果:

11-13 16:22:10.410 31450-31465/? I/System.out: Hello: 0____Thread-2
11-13 16:22:10.410 31450-31466/? I/System.out: Hello: 0____Thread-3
11-13 16:22:10.410 31450-31465/? I/System.out: Hello: 1____Thread-2
11-13 16:22:10.410 31450-31465/? I/System.out: Hello: 2____Thread-2
11-13 16:22:10.410 31450-31466/? I/System.out: Hello: 1____Thread-3
11-13 16:22:10.410 31450-31465/? I/System.out: Hello: 3____Thread-2
11-13 16:22:10.410 31450-31465/? I/System.out: Hello: 4____Thread-2
11-13 16:22:10.410 31450-31465/? I/System.out: Hello: 5____Thread-2
11-13 16:22:10.410 31450-31465/? I/System.out: Hello: 6____Thread-2
11-13 16:22:10.410 31450-31465/? I/System.out: Hello: 7____Thread-2
11-13 16:22:10.410 31450-31466/? I/System.out: Hello: 2____Thread-3
11-13 16:22:10.410 31450-31466/? I/System.out: Hello: 3____Thread-3
11-13 16:22:10.410 31450-31466/? I/System.out: Hello: 4____Thread-3
11-13 16:22:10.411 31450-31466/? I/System.out: Hello: 5____Thread-3
11-13 16:22:10.411 31450-31466/? I/System.out: Hello: 6____Thread-3
11-13 16:22:10.411 31450-31466/? I/System.out: Hello: 7____Thread-3
11-13 16:22:10.411 31450-31465/? I/System.out: Hello: 8____Thread-2
11-13 16:22:10.411 31450-31466/? I/System.out: Hello: 8____Thread-3
11-13 16:22:10.411 31450-31465/? I/System.out: Hello: 9____Thread-2
11-13 16:22:10.411 31450-31466/? I/System.out: Hello: 9____Thread-3

可以看出又不同步了
为什么?
因为run()是静态的,run2()方法不是,这两个方法虽然都是用synchronized修饰,但是锁不是一把,run()的锁是class,而run2()的锁是class对象,不同的锁当然不能同步.

4.synchronized修饰代码块

这个和修饰普通方法差不多,只不过同步的地方是被synchronized包起来的的地方,它的锁取决于这个方法是否是静态的,我们常用的地方就是单例,举个例子:

 public static PushProcess getInstance() {
        if (instance == null) {
            synchronized (PushProcess.class) {
                if (instance == null) {
                    instance = new PushProcess();
                }
            }
        }
        return instance;
    }

可能一个方法中只有几行代码会涉及到线程同步问题,所以synchronized块比synchronized方法更加细粒度地控制了多个线程的访问,只有synchronized块中的内容不能同时被多个线程所访问,方法中的其他语句仍然可以同时被多个线程所访问(包括synchronized块之前的和之后的)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容