synchronized关键字
- synchronized关键字修饰函数方法
使用synchronized关键字时,会获取java对象的内置锁,内置锁会保护整个方法。
public synchronized void add(){
count++;
}
synchronized也可以修饰静态方法,内置锁会锁住整改类。
- synchronized关键字修饰代码块
synchronized可以修饰代码块,只锁住需要保护的代码区域
public class SynchronizedThread {
public void add(){
synchronized(this)
{
count++;
}
}
}
synchronized是一种高开销操作,实际应用不需要锁住整个方法,可以使用同步代码块操作。
使用特殊域变量
使用volatile关键字修饰变量,没有锁同步开销,每次使用变量时需要重新计算,不会直接使用寄存器的值,此变量不是原子操作,不可以修饰final对象。
public class SynchronizedThread{
private volatile int count= 0;
public void add(){
count++;
}
}
使用原子变量实现线程同步
在java的util.concurrent.atomic包中提供了创建了原子类型变量的工具类,使用该类可以简化线程同步。
public class SynchronizedThread{
private AtomicInteger count= new AtomicInteger(0);
public void add(){
count.addAndGet(1);
}
}
原子操作适合线程简单对象的计算。
使用重入锁实现线程同步
在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。ReentrantLock类是可重入、互斥、实现了Lock接口的锁,它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
public class SynchronizedThread{
private int count= 0;
private Lock lock = new ReentrantLock();
public void add(){
lock.lock();
try{
count++;
}finally{
lock.unlock();
}
}
}
使用try模块语句,在finally模块中释放锁,防止死锁。
ReentrantLock类可以构造公平锁,每个线程阻塞相同的时间,但由于能大幅度降低程序运行效率,不推荐使用。
使用局部变量实现线程同步
如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本, 副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
public class SynchronizedThread{
private static ThreadLocal<Integer> count= new ThreadLocal<Integer>(){
@Override
protected Integer initialValue(){
return 0;
}
};
public void add(){
count.set(count.get()+1);
}
}
使用阻塞队列实现线程同步
前面5种同步方式都是在底层实现的线程同步,但是我们在实际开发当中,应当尽量远离底层结构。 使用javaSE5.0版本中新增的java.util.concurrent包将有助于简化开发。 本小节主要是使用LinkedBlockingQueue<E>来实现线程的同步。
public class BlockingSynchronizedThread {
private LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();
private class LinkBlockThread implements Runnable {
@Override
public void run() {
try {
int n = queue.take();
System.out.println(n);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
网友评论