java synchronized关键字

作者: 选一个昵称这么难 | 来源:发表于2017-11-13 16:34 被阅读281次

    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块之前的和之后的)。

    相关文章

      网友评论

        本文标题:java synchronized关键字

        本文链接:https://www.haomeiwen.com/subject/zmyzmxtx.html