synchronized实现线程同步

多线程访问同一个变量时,如果这些线程中既有读操作,又有写操作,就会导致变量值出现混乱。这个时候应该实现线程同步。
synchronized是Java关键字,利用这个关键字可以做到线程同步。

synchronized修饰方法

synchronized用来修饰一个方法时,该方法称为同步方法。对于同一个对象,如果多个线程同时访问其同步方法,同一时刻只有一个线程能获取到该对象的锁,从而执行该同步方法。Hashtable是Java中线程同步的容器,其内部的方法很多都是加了synchronized关键字的。来看看get方法:

public synchronized V get(Object key) {
       int hash = Collections.secondaryHash(key);
        HashtableEntry[] tab = table;
        for (HashtableEntry e = tab[hash & (tab.length - 1)];
                e != null; e = e.next) {
            K eKey = e.key;
            if (eKey == key || (e.hash == hash && key.equals(eKey))) {
                return e.value;
            }
        }
        return null;
    }

synchronized修饰静态方法

synchronized也可以用来修饰静态方法,注意其与直接修复普通方法的区别。修饰静态方法时,不管这个静态方法的类有多少个实例,一次只有一个线程能访问这个静态方法。而修饰普通方法时,每个实例都拥有自己的对象锁,不同实例的同步方法互不影响。

使用懒汉模式的单例时用到的就是synchronized修饰静态方法

  public class Singleton {
          private Singleton() {}
          private static Singleton instance;

          public static synchronized Singleton getInstance() {
            if (instance == null) {
              instance = new Singleton();
            }
            return instance;
          }
        } 

synchronized修饰代码块

synchronized修饰方法时,整个方法都被同步了。由于同步会影响程序性能,所以同步的代码越少越好,这个时候就可以用synchronized同步代码块了。synchronized同步代码块时需要一个参数,这个参数可以是一个实例,也可以是所属类。

一般情况下,可以直接使用this来同步代码块,Picasso的LruCache就是这种方式:

   @Override public Bitmap get(String key) {
        if (key == null) {
          throw new NullPointerException("key == null");
        }

        Bitmap mapValue;
        synchronized (this) {
          mapValue = map.get(key);
          if (mapValue != null) {
            hitCount++;
            return mapValue;
          }
          missCount++;
        }

        return null;
      }

当然,也可以用一个实例化的变量,Android中Message使用一个实例变量来作为同步参数:

private static final Object sPoolSync = new Object();
    public static Message obtain() {
            synchronized (sPoolSync) {
                if (sPool != null) {
                    Message m = sPool;
                    sPool = m.next;
                    m.next = null;
                    m.flags = 0; // clear in-use flag
                    sPoolSize--;
                    return m;
                }
            }
            return new Message();
        }

在static方法中,也可以直接用所属类来作为同步参数,如:

public class MyClass {

        public static void log(String msg1, String msg2){
           synchronized(MyClass.class){
              log.writeln(msg1);
              log.writeln(msg2);  
           }
        }
      }

你可能感兴趣的:(Java)