简单看下不同情况下,它们的效率
1、读多读少的情况(读:1000,写:30)
synchronized
package com.su.mybatis.oracle.controller;
public class Test {
private static int num = 100;
//锁
private static Object obj = new Object();
//读线程数
private static int readThreadNum = 1000;
//写线程数
private static int writeThreadNum = 30;
//开始时间
private static long startTime;
public static void main(String[] args) {
startTime = System.currentTimeMillis();
for(int i = 0; i< readThreadNum; i++) {
//读线程
new Thread(new Runnable(){
@Override
public void run() {
try {
read();
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
for(int i = 0 ; i < writeThreadNum; i++) {
//写线程
new Thread(new Runnable() {
@Override
public void run() {
try {
write();
Thread.sleep(15);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
//读业务
public static void read() throws InterruptedException {
synchronized(obj) {
Thread.sleep(5);
System.out.println("线程(" + Thread.currentThread().getName() + ")执行读业务,num:" + num
+ ",耗时:" + ( System.currentTimeMillis()- startTime)+ "ms");
}
}
//写业务
public synchronized static void write() throws InterruptedException {
synchronized(obj) {
Thread.sleep(10);
num++;
System.out.println("线程(" + Thread.currentThread().getName() + ")执行写业务,num:" + num
+ ",耗时:" + ( System.currentTimeMillis()- startTime)+ "ms");
}
}
}
输出结果:
线程(Thread-0)执行读业务,num:100,耗时:7ms
线程(Thread-55)执行读业务,num:100,耗时:13ms
.
.
.
线程(Thread-1002)执行写业务,num:129,耗时:6103ms
线程(Thread-1001)执行写业务,num:130,耗时:6114ms
ReentrantLock
package com.su.mybatis.oracle.controller;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test {
private static int num = 100;
//重入锁
private final static Lock lock = new ReentrantLock();
//读线程数
private static int readThreadNum = 1000;
//写线程数
private static int writeThreadNum = 30;
//开始时间
private static long startTime;
public static void main(String[] args) {
startTime = System.currentTimeMillis();
for(int i = 0; i< readThreadNum; i++) {
//读线程
new Thread(new Runnable(){
@Override
public void run() {
try {
read();
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
for(int i = 0 ; i < writeThreadNum; i++) {
//写线程
new Thread(new Runnable() {
@Override
public void run() {
try {
write();
Thread.sleep(15);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
//读业务
public static void read() throws InterruptedException {
try {
lock.lock();
Thread.sleep(5);
System.out.println("线程(" + Thread.currentThread().getName() + ")执行读业务,num:" + num
+ ",耗时:" + ( System.currentTimeMillis()- startTime)+ "ms");
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
//写业务
public synchronized static void write() throws InterruptedException {
try {
lock.lock();
Thread.sleep(10);
num++;
System.out.println("线程(" + Thread.currentThread().getName() + ")执行写业务,num:" + num
+ ",耗时:" + ( System.currentTimeMillis()- startTime)+ "ms");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
输出结果:
线程(Thread-0)执行读业务,num:100,耗时:7ms
线程(Thread-1)执行读业务,num:100,耗时:14ms
.
.
.
线程(Thread-1002)执行写业务,num:129,耗时:6154ms
线程(Thread-1001)执行写业务,num:130,耗时:6165ms
ReentrantReadWriteLock
package com.su.mybatis.oracle.controller;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Test {
private static int num = 100;
//读写锁
private static ReadWriteLock lock = new ReentrantReadWriteLock();
//读锁
private static Lock r = lock.readLock();
//写锁
private static Lock w = lock.writeLock();
//读线程数
private static int readThreadNum = 1000;
//写线程数
private static int writeThreadNum = 30;
//开始时间
private static long startTime;
public static void main(String[] args) {
startTime = System.currentTimeMillis();
for(int i = 0; i< readThreadNum; i++) {
//读线程
new Thread(new Runnable(){
@Override
public void run() {
try {
read();
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
for(int i = 0 ; i < writeThreadNum; i++) {
//写线程
new Thread(new Runnable() {
@Override
public void run() {
try {
write();
Thread.sleep(15);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
//读业务
public static void read() throws InterruptedException {
try {
r.lock();
Thread.sleep(5);
System.out.println("线程(" + Thread.currentThread().getName() + ")执行读业务,num:" + num
+ ",耗时:" + ( System.currentTimeMillis()- startTime)+ "ms");
} catch (Exception e) {
e.printStackTrace();
}finally {
r.unlock();
}
}
//写业务
public synchronized static void write() throws InterruptedException {
try {
w.lock();
Thread.sleep(10);
num++;
System.out.println("线程(" + Thread.currentThread().getName() + ")执行写业务,num:" + num
+ ",耗时:" + ( System.currentTimeMillis()- startTime)+ "ms");
} catch (Exception e) {
e.printStackTrace();
} finally {
w.unlock();
}
}
}
输出结果:
线程(Thread-1)执行读业务,num:100,耗时:8ms
线程(Thread-3)执行读业务,num:100,耗时:8ms
.
.
.
线程(Thread-1002)执行写业务,num:129,耗时:497ms
线程(Thread-1001)执行写业务,num:130,耗时:508ms
2、写多读少的情况(读:30,写:1000)
将上面代码中读线程数和写线程数交换
synchronized
输出结果:
线程(Thread-0)执行读业务,num:100,耗时:7ms
线程(Thread-30)执行写业务,num:101,耗时:18ms
.
.
.
线程(Thread-151)执行写业务,num:1099,耗时:10861ms
线程(Thread-150)执行写业务,num:1100,耗时:10872ms
ReentrantLock
输出结果:
线程(Thread-0)执行读业务,num:100,耗时:7ms
线程(Thread-1)执行读业务,num:100,耗时:13ms
.
.
.
线程(Thread-32)执行写业务,num:1099,耗时:10909ms
线程(Thread-31)执行写业务,num:1100,耗时:10920ms
ReentrantReadWriteLock
输出结果:
线程(Thread-4)执行读业务,num:100,耗时:7ms
线程(Thread-3)执行读业务,num:100,耗时:7ms
.
.
.
线程(Thread-140)执行写业务,num:1099,耗时:10691ms
线程(Thread-141)执行写业务,num:1100,耗时:10702ms
对比:
1)、synchronized关键字是jdk提供的语言层次的内置锁,是不公平锁,ReentrantLock是显示锁,可以指定是否为公平锁,使用时是需要进行实例化,会占据一定的资源(如:内存等),在性能上,synchronized略优于ReentrantLock;
2)、使用上,ReentrantLock更加灵活,synchronized会自动释放锁,而使用ReentrantLock则要记得释放锁;
3)、ReentrantLock提供了特殊需求,如超时获取、,尝试非阻塞获取锁等;
结论:没有特殊需求,尽可能使用synchronized,有特殊需求,考虑ReentrantLock;同时存在读操作和写操作时,使用ReentrantReadWriteLock,读操作越多,性能优势越明显。
如果有写的不对的地方,请大家多多批评指正,非常感谢!