今天来到江宁的亲子阅读室,看到这些祖国的未来,顿时搞到自己写代码也充满了希望,哈哈。

图片

万物之中,希望最美....





synchronized 和 Lock 之间的区别

  • 实现层面不一样。synchronized 是 Java 关键字,JVM层面 实现加锁和释放锁;Lock 是一个接口,在代码层面实现加锁和释放锁

  • 是否自动释放锁。synchronized 在线程代码执行完或出现异常时自动释放锁;Lock 不会自动释放锁,需要在 finally {} 代码块显式地中释放锁

  • 是否一直等待。synchronized 会导致线程拿不到锁一直等待;Lock 可以设置尝试获取锁或者获取锁失败一定时间超时

  • 获取锁成功是否可知。synchronized 无法得知是否获取锁成功;Lock 可以通过 tryLock 获得加锁是否成功

  • 功能复杂性。synchronized 加锁可重入、不可中断、非公平;Lock 可重入、可判断、可公平和不公平、细分读写锁提高效率

 

Lock 与  ReadWriteLock 之间的区别

  • ReadWriteLock 定义了获取读锁和写锁的接口,读锁之间不互斥,非常适合读多、写少的场景

 

适用场景

  • JDK 1.6 开始,对 synchronized 方式枷锁进行了优化,加入了偏向锁、轻量级锁和锁升级机制,性能得到了很大的提升。性能与 ReentrantLock  差不多

  • 读多写少的情况下,考虑使用 ReadWriteLock 

 

synchronized、ReentrantLock、ReentrantReadWriteLock 启动 990 个线程读共享变量,10 个线程写共享变量

package constxiong.concurrency.a020;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
* JDK 1.8 中锁性能的测试
* @author ConstXiong
*/

public class TestLockPerformance {

public static Object obj = new Object();//用于 synchronized 获取锁

public static Lock lock = new ReentrantLock();//可重入锁

public static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();//读写锁

public static final int READ = 0;

public static final int WRITE = 1;

// uuid,一个随机字符串
public static String uuid = UUID.randomUUID().toString();

public static void main(String[] args) throws InterruptedException {
//testSynchronized(1000);

testReentrantLock(1000);

//testReadWriteLock(1000);
}

public static void testSynchronized(int threadNum) throws InterruptedException {
long t1 = System.currentTimeMillis();
List<Thread> tList = new ArrayList<Thread>();
//启动 threadNum - 向上取整 (0.01 * threadNum) 个线程读 uuid, 向上取整 (0.01 * threadNum) 个线程写 uuid
for (int i = 0; i < threadNum; i++) {
Thread t;
if (i % 100 == 0) {
t = new Thread(new WorkerSynchronized(WRITE));
} else {
t = new Thread(new WorkerSynchronized(READ));
}
t.start();//启动线程
tList.add(t);
}

for (Thread t : tList) {
t.join();
}

long t2 = System.currentTimeMillis();
System.out.println("testSynchronized 耗时:" + (t2 - t1));
}

public static void testReentrantLock(int threadNum) throws InterruptedException {
long t1 = System.currentTimeMillis();
List<Thread> tList = new ArrayList<Thread>();
//启动 threadNum - 向上取整 (0.01 * threadNum) 个线程读 uuid, 向上取整 (0.01 * threadNum) 个线程写 uuid
for (int i = 0; i < threadNum; i++) {
Thread t;
if (i % 100 == 0) {
t = new Thread(new WorkerReentrantLock(WRITE));
} else {
t = new Thread(new WorkerReentrantLock(READ));
}
t.start();//启动线程
tList.add(t);
}

for (Thread t : tList) {
t.join();
}

long t2 = System.currentTimeMillis();
System.out.println("testReentrantLock 耗时:" + (t2 - t1));
}

public static void testReadWriteLock(int threadNUm) throws InterruptedException {
long t1 = System.currentTimeMillis();
List<Thread> tList = new ArrayList<Thread>();
//启动 threadNum - 向上取整 (0.01 * threadNum) 个线程读 uuid, 向上取整 (0.01 * threadNum) 个线程写 uuid
for (int i = 0; i < threadNUm; i++) {
Thread t;
if (i % 100 == 0) {
t = new Thread(new WorkerReadWriteLock(WRITE));
} else {
t = new Thread(new WorkerReadWriteLock(READ));
}
t.start();//启动线程
tList.add(t);
}

for (Thread t : tList) {
t.join();
}

long t2 = System.currentTimeMillis();
System.out.println("testReadWriteLock 耗时:" + (t2 - t1));
}

}

//工作线程,使用 synchronized 关键字加锁
class WorkerSynchronized implements Runnable {
//0-read;1-write
private int type;

WorkerSynchronized(int type) {
this.type = type;
}

//加锁读 TestLockPerformance.uuid 变量,并打印
private void read() {
synchronized (TestLockPerformance.obj) {
//休眠 20 毫秒,模拟任务执行耗时
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
" read uuid = " +  TestLockPerformance.uuid);
}
}

//加锁写 TestLockPerformance.uuid 变量,并打印
private void write() {
synchronized (TestLockPerformance.obj) {
//休眠 20 毫秒,模拟任务执行耗时
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
TestLockPerformance.uuid = UUID.randomUUID().toString();
System.out.println(Thread.currentThread().getName() +
" write uuid = " +  TestLockPerformance.uuid);
}
}

@Override
public void run() {
//type = 0,线程读 TestLockPerformance.uuid 变量
if (type == 0) {
read();
//type = 1,线程生成 uuid,写入 TestLockPerformance.uuid 变量
} else {
write();
}
}
}

//工作线程,使用 ReentrantLock 加锁
class WorkerReentrantLock implements Runnable {
//0-read;1-write
private int type;

WorkerReentrantLock(int type) {
this.type = type;
}

//加锁读 TestLockPerformance.uuid 变量,并打印
private void read() {
TestLockPerformance.lock.lock();
try {
//休眠 20 毫秒,模拟任务执行耗时
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
" read uuid = " +  TestLockPerformance.uuid);
} finally {
TestLockPerformance.lock.unlock();
}

}

//加锁写 TestLockPerformance.uuid 变量,并打印
private void write() {
TestLockPerformance.lock.lock();
try {
//休眠 20 毫秒,模拟任务执行耗时
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
TestLockPerformance.uuid = UUID.randomUUID().toString();
System.out.println(Thread.currentThread().getName() +
" write uuid = " +  TestLockPerformance.uuid);
} finally {
TestLockPerformance.lock.unlock();
}
}

@Override
public void run() {
//type = 0,线程读 TestLockPerformance.uuid 变量
if (type == 0) {
read();
//type = 1,线程生成 uuid,写入 TestLockPerformance.uuid 变量
} else {
write();
}
}
}


//工作线程,使用 ReentrantReadWriteLock 关键字加锁
class WorkerReadWriteLock implements Runnable {
//0-read;1-write
private int type;

WorkerReadWriteLock(int type) {
this.type = type;
}

//加锁读 TestLockPerformance.uuid 变量,并打印
private void read() {
TestLockPerformance.readWriteLock.readLock().lock();
try {
//休眠 20 毫秒,模拟任务执行耗时
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
" read uuid = " +  TestLockPerformance.uuid);
} finally {
TestLockPerformance.readWriteLock.readLock().unlock();
}
}

//加锁写 TestLockPerformance.uuid 变量,并打印
private void write() {
TestLockPerformance.readWriteLock.writeLock().lock();
try {
//休眠 20 毫秒,模拟任务执行耗时
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
TestLockPerformance.uuid = UUID.randomUUID().toString();
System.out.println(Thread.currentThread().getName() +
" write uuid = " +  TestLockPerformance.uuid);
} finally {
TestLockPerformance.readWriteLock.writeLock().unlock();
}
}

@Override
public void run() {
//type = 0,线程读 TestLockPerformance.uuid 变量
if (type == 0) {
read();
//type = 1,线程生成 uuid,写入 TestLockPerformance.uuid 变量
} else {
write();
}
}
}

 

调用测试方法 

testSynchronized(1000);

耗时

Thread-0 write uuid = b7fb63d7-79cc-4cc0-84ed-5a9cd4de6824
Thread-252 read uuid = b7fb63d7-79cc-4cc0-84ed-5a9cd4de6824
Thread-251 read uuid = b7fb63d7-79cc-4cc0-84ed-5a9cd4de6824
.
.
.
Thread-255 read uuid = d666bfe6-dc71-4df2-882a-d530a59d7e92
Thread-254 read uuid = d666bfe6-dc71-4df2-882a-d530a59d7e92
Thread-253 read uuid = d666bfe6-dc71-4df2-882a-d530a59d7e92
testSynchronized 耗时:22991

 

调用测试方法 

testReentrantLock(1000);

耗时

Thread-0 write uuid = 4352eb13-d284-47ec-8caa-fc81d91d08e1
Thread-1 read uuid = 4352eb13-d284-47ec-8caa-fc81d91d08e1
Thread-485 read uuid = 4352eb13-d284-47ec-8caa-fc81d91d08e1
.
.
.
Thread-997 read uuid = 9d7f0a78-5eb7-4506-9e98-e8e9a7a717a5
Thread-998 read uuid = 9d7f0a78-5eb7-4506-9e98-e8e9a7a717a5
Thread-999 read uuid = 9d7f0a78-5eb7-4506-9e98-e8e9a7a717a5
testReentrantLock 耗时:22935

 

调用测试方法 

testReadWriteLock(1000);

耗时

Thread-0 write uuid = 81c13f80-fb19-4b27-9d21-2e99f8c8acbd
Thread-277 read uuid = 81c13f80-fb19-4b27-9d21-2e99f8c8acbd
Thread-278 read uuid = 81c13f80-fb19-4b27-9d21-2e99f8c8acbd
.
.
.
Thread-975 read uuid = 35be0359-1973-4a4f-85b7-918053d841f7
Thread-971 read uuid = 35be0359-1973-4a4f-85b7-918053d841f7
Thread-964 read uuid = 35be0359-1973-4a4f-85b7-918053d841f7
testReadWriteLock 耗时:543

 

通过耗时测试可以看出,使用 synchronized 和 ReentrantLock 耗时相近;但是由于 990 个线程读,10 个线程写,使用 ReentrantReadWriteLock 耗时 543 毫秒。

 

PS:JDK 并发包里的工具类,还有很多适合特定场景的工具,后面我们继续探索。


更多相关文章

  1. Executors如何创建线程池?
  2. 什么是线程?什么是进程?为什么要有线程?有什么关系与区别?
  3. 什么是线程池?
  4. 线程包括哪些状态?状态之间是如何转变的?
  5. 什么是守护线程?
  6. 如何优雅地停止一个线程?
  7. java多线程(11)AtomicBoolean原子类分析
  8. Java基础系列:线程同步和线程池
  9. java多线程(6)sleep和wait的4大区别

随机推荐

  1. python函数小练习
  2. python 读写json数据
  3. 在Python中解析Yaml:检测重复的密钥
  4. 批量重命名文件——python实现
  5. 用15行perl打造win32下的简易后门 python
  6. python使用多进程爬取图片
  7. Python 3.4 AssertEqual()在Django单元测
  8. pandas - 将嵌套字典值映射到dataframe
  9. 【python coding 1:网络检测】ping本地文
  10. 在Python中搜索一个并行数组