互联网常常提及的三高问题到底指的是什么?高性能、高扩展、高并发。
“synchronized”锁
实现细节:
1、字节码层面:通过monitorenter和monitorexit指令,就可以实现synchronized了。
2、JVM层面:调用操作系统提供的同步机制。
3、os和硬件层面:实际是lock一条指令。
高性能是互联网三高问题重重之重。我们可以容忍系统较弱的扩展能力,以及系统的并发访问数,往往不能容纳系统极低的性能。
高性能指标一般指两方面的内容:
1、响应时间:低延时
2、吞吐量:高吞吐
“优化系统”一般也是从这两方面入手。所以降低延时,提供吞吐,是我们优化系统的切入点。
Amdahl's law
- 对系统某部分加速时,其对系统整体影响取决于该部分重要性和加速程度。
- 要想显著加速整个系统,必须提升全系统中相当大的部分的速度。
如果有一个应用程序完成一项任务需要时间为Told,该应用程序某部分执行时间与总时间比例为α,
若将该部分性能提升k倍,总的执行时间为:
Tnew = (αTold / k) + (Told - αTold)
= Told [ (1 - α) + α/k ]
加速比 S = Told / Tnew
举几个例子:
集群——>吞吐
负载均衡——>吞吐
缓存——>响应
MQ异步——>吞吐
分库分表——>吞吐&响应
JVM优化——>响应
Tomcat非阻塞协议——>响应
多线程——>吞吐
注意:加速响应时间的同时,必然会提高吞吐量。大吞吐不一定响应就快。
多线程:指程序工作过程中开辟多个工作线程来并行操作,以提高系统吞吐量。
那么问题来了,问题一、线程数是越多越好吗?问题二、单核CPU设定多线程是否有意义?问题三、工作线程数设置多少合适?
首先先来回答问题一当然不是越多越好。
-
服务器CPU核数有限,能够同时并发的线程数有限,单核CPU设置10000个工作线程没有意义
-
线程切换是有开销的,如果线程切换过于频繁,反而会使性能降低
线程无限创建抛出异常:Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
然后是问题二,单核CPU也可以通过多线程来并发工作,所以单核CPU多线程也是有意义的。单核CPU当某一线程逻辑耗时时间比较长(一些等待的任务实现上如用户输入、文件读写和网络收发数据等),或者由于某种原因挂起,其他线程就会获取到CPU时间片来工作。
JDK演进历程:1.4 1.5 1.6 1.7 1.8 1.9 10 11 12 13 14 15...
多线程三大特性:可见性、有序性、原子性
/* */ private Lock getLock(String lockKey) {
/* 167 */ Lock l = (Lock)this.locks.get(lockKey);
/* 168 */ if (l == null) {
/* 169 */ synchronized (this.lock) {
/* 170 */ l = (Lock)this.locks.get(lockKey);
/* 171 */ if (l == null) {
/* 172 */ l = new ReentrantLock();
/* 173 */ this.locks.put(lockKey, l);
/* */ }
/* */ }
/* */ }
/* 177 */ return l;
/* */ }
获取锁代码片段。
/* */ private String nextOid(String sid)
/* */ {
/* 102 */ if (StringUtils.isBlank(sid)) {
/* 103 */ sid = "uapcloud";
/* */ }
/* */
/* 106 */ String key = sid;
/* 107 */ if (StringUtils.isBlank(key)) {
/* 108 */ throw new RuntimeException("schema code can not be null! please check global conf and context info!");
/* */ }
/* */
/* */
/* 112 */ Lock l = getLock(key);
/* */
/* 114 */ OidCounter oidCounter = null;
/* 115 */ String oidBase = null;
/* 116 */ String nextOid = null;
/* */
/* */ try
/* */ {
/* 120 */ l.lock();
/* */
/* 122 */ oidCounter = (OidCounter)oidMap.get(key);
/* 123 */ if (oidCounter == null) {
/* 124 */ oidCounter = new OidCounter();
/* 125 */ oidMap.put(key, oidCounter);
/* */ }
/* */
/* 128 */ if ((oidCounter.amount % OID_AMOUNT == 0) || (0 == oidCounter.amount)) {
/* 129 */ oidBase = getNewBaseId(key);
/* */ } else {
/* 131 */ oidBase = oidCounter.oidBase;
/* */ }
/* */
/* 134 */ nextOid = UapOidAlgorithm.getInstance(oidBase).nextOidBase();
/* 135 */ oidCounter.oidBase = nextOid;
/* 136 */ oidCounter.amount += 1;
/* */ } catch (Exception e) {
/* 138 */ LOGGER.error("get oid error!", e);
/* 139 */ throw e;
/* */ }
/* */ finally {
/* 142 */ l.unlock();
/* */ }
/* */
/* 145 */ if (nextOid == null) {
/* 146 */ return null;
/* */ }
/* */
/* 149 */ return getWholeOid(sid, nextOid);
/* */ }
Lock使用代码示例。