多线程同步方式
线程之间的同步需要用到“锁”来保护代码,以保证对于共享数据进行有序化读写。java中锁又分为独占锁和读写锁。独占锁是一种公平锁,任何时刻,最多只有一个线程(读或写)进入被保护的代码块;读写锁是一种非公平锁,包含了读锁和写锁,允许共享读,但读写互斥、写写互斥。在读多写少的场合使用读写锁比使用独占锁效率要高得多。
java多线程同步方式有四种:join,synchronized,wait/notify,ReadWriteLock。后面的三种机制都需要用到锁。
join
挂起当前线程,待其他线程执行完毕后再恢复当前线程,力度非常粗,只用于一些特定场合,比如后面的线程需要用到前面线程的处理结果。如下:
(1)Thread test=new TestThread();
(2)test.start();
(3)test.join();
(4)System.out.println("test");
第(3)步执行完毕后,当前线程挂起,等待test线程执行结束,然后当前线程恢复就绪,待时间片到来时执行第(4)步。
synchronized
synchronized是jdk原生的线程同步方案,实际上就是独占锁机制,java中所有的Object都有一个隐藏的锁,对于实例方法的保护,用当前对象作为锁,对于类方法则用类对象作为锁。如下:
public class Test{
public synchronized void test1(){
System.out.println("test1");
}
public synchronized static void test2(){
System.out.println("test2");
}
}
其中test1方法是实例方法,等价于
public void test1(){
synchronized(this ){
System.out.println("test1");
}
}
test2方法是类方法,等价于
public static void test2(){
synchronized(Test.class ){
System.out.println("test2");
}
}
另外synchronized还可以加到属性字段上,其实意思都差不多,在操作该属性时会自动地加上当前对象锁(实例属性)或类锁(类属性)。
wait/notify
wait/notify是在synchronized的基础上加入了等待/通知功能,使得线程间的同步更为灵活。但是在锁对象上,同步锁不再限于当前实例对象或类对象,可以使用任何非空对象,如下:
Object lock=new Object();
synchronized(lock){
try {
lock.wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
ReadWriteLock
从根本上讲,synchronized与wait/notify是一样的,都是基于独占锁,只不过后者在前者的基础上做了功能上的扩充。ReadWriteLock是一个更为强大的锁机制,因为他允许共享读,大大降低了读并发时的上锁消耗。客观地讲,与独占互斥锁定相比,使用读写锁定能否提升性能则取决于读写操作期间读取数据相对于修改数据的频率。实例代码如下:
ReadWriteLock rw=new ReentrantReadWriteLock();
Lock rl=rw.readLock();
Lock wl=rw.writeLock();
//读共享数据
rl.lock();
try{
/////////////
}finally{
rl.unlock();
}
//写共享数据
wl.lock();
try{
//////////////
}finally{
wl.unlock();
}