美文网首页
synchronized

synchronized

作者: hey_leex | 来源:发表于2018-01-05 17:12 被阅读0次

    synchronized

    synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:

    1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
    2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
    3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
    4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

    修饰一个代码块

    一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞

    class SyncThread implements Runnable {
       private static int count;
    
       public SyncThread() {
          count = 0;
       }
    
       public  void run() {
          synchronized(SyncThread.class) {
             for (int i = 0; i < 5; i++) {
                try {
                   System.out.println(Thread.currentThread().getName() + ":" + (count++));
                   Thread.sleep(100);
                } catch (InterruptedException e) {
                   e.printStackTrace();
                }
             }
          }
       }
    
       public int getCount() {
          return count;
       }
    }
    //----------------
    SyncThread syncThread = new SyncThread();
    Thread thread1 = new Thread(syncThread, "SyncThread1");
    Thread thread2 = new Thread(syncThread, "SyncThread2");
    thread1.start();
    thread2.start();
    //----------------
    

    修饰一个方法

    Synchronized修饰一个方法很简单,就是在方法的前面加synchronized,

    public synchronized void method(){//todo}; 
    

    synchronized修饰方法和修饰一个代码块类似,只是作用范围不一样,修饰代码块是大括号括起来的范围,而修饰方法范围是整个函数

    public synchronized void run() {
       for (int i = 0; i < 5; i ++) {
          try {
             System.out.println(Thread.currentThread().getName() + ":" + (count++));
             Thread.sleep(100);
          } catch (InterruptedException e) {
             e.printStackTrace();
          }
       }
    }
    

    在用synchronized修饰方法时要注意以下几点:

    1. synchronized关键字不能继承。

      虽然可以使用synchronized来定义方法,但synchronized并不属于方法定义的一部分,因此,synchronized关键字不能被继承。如果在父类中的某个方法使用了synchronized关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上synchronized关键字才可以。当然,还可以在子类方法中调用父类中相应的方法,这样虽然子类中的方法不是同步的,但子类调用了父类的同步方法,因此,子类的方法也就相当于同步了。

      这两种方式的例子代码如下:

      在子类方法中加上synchronized关键字

       class Parent {
          public synchronized void method() { }
       }
       class Child extends Parent {
          public synchronized void method() { }
       }
      

      在子类方法中调用父类的同步方法

       class Parent {
          public synchronized void method() {   }
       }
       class Child extends Parent {
          public void method() { super.method();   }
       } 
      
    2. 在定义接口方法时不能使用synchronized关键字。

    3. 构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步。

    修饰一个静态的方法

    class SyncThread implements Runnable {
       private static int count;
    
       public SyncThread() {
          count = 0;
       }
    
       public synchronized static void method() {
          for (int i = 0; i < 5; i ++) {
             try {
                System.out.println(Thread.currentThread().getName() + ":" + (count++));
                Thread.sleep(100);
             } catch (InterruptedException e) {
                e.printStackTrace();
             }
          }
       }
    
       public synchronized void run() {
          method();
       }
    }
    

    syncThread1和syncThread2是SyncThread的两个对象,但在thread1和thread2并发执行时却保持了线程同步。这是因为run中调用了静态方法method,而静态方法是属于类的,所以syncThread1和syncThread2相当于用了同一把锁。这与Demo1是不同的。

    修饰一个类

    class SyncThread implements Runnable {
       private static int count;
    
       public SyncThread() {
          count = 0;
       }
    
       public static void method() {
          synchronized(SyncThread.class) {
             for (int i = 0; i < 5; i ++) {
                try {
                   System.out.println(Thread.currentThread().getName() + ":" + (count++));
                   Thread.sleep(100);
                } catch (InterruptedException e) {
                   e.printStackTrace();
                }
             }
          }
       }
    
       public synchronized void run() {
          method();
       }
    }
    

    总结

    1. 无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。
    2. 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。
    3. 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。

    相关文章

      网友评论

          本文标题:synchronized

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