【发布时间】:2019-10-20 09:03:52
【问题描述】:
我创建了 1000 个线程来递增,1000 个线程来递减,1000 个线程来读取值。
每增加一个线程,值增加25000倍。
每个递减线程,减值25000倍。
每个读取线程,读取值50000次。
所以所有的操作都是读取主导的。
读取值时放置ReadLock
WriteLock 用于递增和递减值的方法。
观察到:ReentrantReadWriteLock 大约需要 13000 毫秒 锁定大约需要 3000 毫秒。 预期:ReentrantReadWriteLock 提供比 ReentrantLock 更快的性能。
顺便说一句:我个人认为使用 getCounter 方法时不需要锁定/同步(只是读取值)
import java.util.ArrayList;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Main {
public static void main(String[] args) throws InterruptedException {
ArrayList<Thread> reads = new ArrayList<>();
ArrayList<Thread> increments = new ArrayList<>();
ArrayList<Thread> decrements = new ArrayList<>();
Resources resources = new Resources();
long start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
Thread read = new Read(resources);
Thread increment = new Increment(resources);
Thread decrement = new Decrement(resources);
reads.add(read);
increments.add(increment);
decrements.add(decrement);
read.start();
increment.start();
decrement.start();
}
for (int i = 0; i < 1000; i++) {
reads.get(i).join();
increments.get(i).join();
decrements.get(i).join();
}
System.out.println(resources.getCounter());
System.out.println(System.currentTimeMillis() - start);
}
private static abstract class UserThread extends Thread {
protected Resources resources;
public UserThread(Resources resources) {
this.resources = resources;
}
}
private static class Read extends UserThread {
public Read(Resources resources) {
super(resources);
}
public void run() {
for (int i = 0; i < 50000; i++) {
resources.getCounter();
}
}
}
private static class Increment extends UserThread {
public Increment(Resources resources) {
super(resources);
}
public void run() {
for (int i = 0; i < 25000; i++) {
resources.increment();
}
}
}
private static class Decrement extends UserThread {
public Decrement(Resources resources) {
super(resources);
}
public void run() {
for (int i = 0; i < 25000; i++) {
resources.decrement();
}
}
}
private static class Resources {
private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
private ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();
private ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
private ReentrantLock lock = new ReentrantLock();
public int getCounter() {
readLock.lock();
try {
return counter;
} finally {
readLock.unlock();
}
}
private int counter = 0;
public void increment() {
writeLock.lock();
try {
counter++;
} finally {
writeLock.unlock();
}
}
public void decrement() {
writeLock.lock();
try {
counter--;
} finally {
writeLock.unlock();
}
}
}
}
【问题讨论】:
-
您说代码是“读取主导”,但您的递增和递减线程加起来是 50,000 次操作,这与您的读取线程执行的操作数相同。另外,你的写作线程数是阅读线程数的两倍。
ReadWriteLock在读多写少的情况下效果最好。 -
你的线程都是 100% CPU-bound,即没有 I/O。使用这样的线程,创建比虚拟核心(核心 + 超线程)更多的线程实际上会运行更慢,因为你现在强制进行过多的上下文切换。您的机器上有 3000 个虚拟内核吗?
标签: java multithreading reentrantlock reentrantreadwritelock