并发编程陷阱系列(七)读多写少使用synchronized导致性能下降
程序员文章站
2022-04-05 14:45:01
...
对并发读的情况进行测试:
public class SynchronizedDemo { static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static void main(String[] args) throws Exception { Data data = new Data(); Worker t1 = new Worker(data, true, "t1"); Worker t2 = new Worker(data, true, "t2"); t1.start(); t2.start(); } static class Worker extends Thread { Data data; boolean read; public Worker(Data data, boolean read, String threadName) { super(threadName); this.data = data; this.read = read; } public void run() { if (read) data.get(); else data.set(); } } /** * 数据类 */ static class Data { /** * 写数据 */ public synchronized void set() { System.out.println(Thread.currentThread().getName() + " set:begin " + sdf.format(new Date())); try { Thread.sleep(5000); } catch (Exception e) { } finally { System.out.println(Thread.currentThread().getName() + " set:end " + sdf.format(new Date())); } } /** * 读数据 */ public synchronized int get() { System.out.println(Thread.currentThread().getName() + " get :begin " + sdf.format(new Date())); try { Thread.sleep(5000); } catch (Exception e) { } finally { System.out.println(Thread.currentThread().getName() + " get :end " + sdf.format(new Date())); } return 1; } } }
synchronized执行的结果:
t1 get :begin 2013-05-06 22:57:50
t1 get :end 2013-05-06 22:57:55
t2 get :begin 2013-05-06 22:57:55
t2 get :end 2013-05-06 22:58:00
t1先执行,t1 结束后;t2再开始执行,直到结束。对象的方法中一旦加入synchronized修饰,则任何时刻只能有一个线程访问synchronized修饰的方法,所以我们看到结果中是串行执行的。
public class ReadWriteLockDemo { static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static void main(String[] args) throws Exception { Data data = new Data(); Worker t1 = new Worker(data, true, "t1"); Worker t2 = new Worker(data, true, "t2"); t1.start(); t2.start(); } static class Worker extends Thread { Data data; boolean read; public Worker(Data data, boolean read, String threadName) { super(threadName); this.data = data; this.read = read; } public void run() { if (read) data.get(); else data.set(); } } /** * 数据类 */ static class Data { ReadWriteLock lock = new ReentrantReadWriteLock(); Lock read = lock.readLock(); Lock write = lock.writeLock(); /** * 写数据 */ public void set() { write.lock(); System.out.println(Thread.currentThread().getName() + " set:begin " + sdf.format(new Date())); try { Thread.sleep(5000); } catch (Exception e) { } finally { System.out.println(Thread.currentThread().getName() + " set:end " + sdf.format(new Date())); write.unlock(); } } /** * 读数据 */ public int get() { read.lock(); System.out.println(Thread.currentThread().getName() + " get :begin " + sdf.format(new Date())); try { Thread.sleep(5000); } catch (Exception e) { } finally { System.out.println(Thread.currentThread().getName() + " get :end " + sdf.format(new Date())); read.unlock(); } return 1; } } }
使用读锁的执行结果:
t1 get :begin 2013-05-06 23:00:41
t2 get :begin 2013-05-06 23:00:41
t1 get :end 2013-05-06 23:00:46
t2 get :end 2013-05-06 23:00:46
这两个线程同时开始,同时结束。读锁允许多个线程共同读取资源(没有其他线程获取到写锁或者没有正在写数据)。