synchronized实现线程同步

xiaoxiao2021-02-28  109

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

synchronized修饰方法

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

public synchronized V get(Object key) { int hash = Collections.secondaryHash(key); HashtableEntry<K, V>[] tab = table; for (HashtableEntry<K, V> 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); } } }
转载请注明原文地址: https://www.6miu.com/read-53667.html

最新回复(0)