This commit is contained in:
parent
9f31a3f918
commit
5e19e11719
|
@ -71,14 +71,14 @@
|
|||
{% endif %}
|
||||
<span>最新构建于: {{ site.time | date: "%Y-%m-%d %H:%M" }}</span><br><br>
|
||||
<span>
|
||||
<a href="http://www.beian.miit.gov.cn" rel="nofollow">闽ICP备19012687号</a>
|
||||
<a href="http://beian.miit.gov.cn" rel="nofollow">闽ICP备17033777号</a>
|
||||
</span><br><br>
|
||||
<span>开源地址: https://gitee.com/apihub/feling.net</span>
|
||||
</div>
|
||||
{% if page.url contains "/pages/" or page.url contains "/rank/" %}
|
||||
<script>
|
||||
<!-- <script>
|
||||
(adsbygoogle = window.adsbygoogle || []).push({});
|
||||
</script>
|
||||
</script> -->
|
||||
{% else %}
|
||||
<script>
|
||||
if (localStorage.shyFooter == 'true') {
|
||||
|
@ -87,7 +87,7 @@
|
|||
$('#shy-footer-on').show()
|
||||
$('#shy-footer-off').hide()
|
||||
} else {
|
||||
(adsbygoogle = window.adsbygoogle || []).push({});
|
||||
// (adsbygoogle = window.adsbygoogle || []).push({});
|
||||
$('#shy-footer-on').hide()
|
||||
$('#shy-footer-off').show()
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<ul class="uk-navbar-nav">
|
||||
<li
|
||||
{% if page.url contains "/json/" %}class="uk-active"{% endif %}
|
||||
{% if page.url contains "/jwt/" %}class="uk-active"{% endif %}
|
||||
{% if page.url contains "/base64/" %}class="uk-active"{% endif %}
|
||||
{% if page.url contains "/unicode/" %}class="uk-active"{% endif %}
|
||||
{% if page.url contains "/wsp/" %}class="uk-active"{% endif %}
|
||||
|
@ -27,6 +28,7 @@
|
|||
|
||||
<li class="uk-nav-divider"></li>
|
||||
<li><a href="/json/">Json 格式化</a></li>
|
||||
<li><a href="/jwt/">JWT 解码</a></li>
|
||||
<li><a href="/wsp/">WebSocket 联调</a></li>
|
||||
<li><a href="/base64/">Base64 编解码</a></li>
|
||||
<li><a href="/unicode/">\uxxxx 转中文</a></li>
|
||||
|
@ -47,6 +49,7 @@
|
|||
<div class="uk-navbar-flip">
|
||||
<ul class="uk-navbar-nav uk-hidden-small" >
|
||||
{% if page.url contains "/json/" %}{% else %}<li><a href="/json/">Json 格式化</a></li>{% endif %}
|
||||
{% if page.url contains "/jwt/" %}{% else %}<li><a href="/jwt/">JWT 解码</a></li>{% endif %}
|
||||
{% if page.url contains "/base64/" %}{% else %}<li><a href="/base64/">Base64 编解码</a></li>{% endif %}
|
||||
{% if page.url contains "/wsp/" %}{% else %}<li><a href="/wsp/">WebSocket 联调</a></li>{% endif %}
|
||||
<li><a href="/">更多 <i class="uk-icon-angle-double-right"></i></a></li>
|
||||
|
|
|
@ -140,9 +140,9 @@ layout: default
|
|||
style="display:inline-block;width:336px;height:280px"
|
||||
data-ad-client="ca-pub-3779740765441924"
|
||||
data-ad-slot="6169161876"></ins>
|
||||
<script>
|
||||
<!-- <script>
|
||||
(adsbygoogle = window.adsbygoogle || []).push({});
|
||||
</script>
|
||||
</script> -->
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -229,7 +229,7 @@ layout: default
|
|||
$('#x-left-content').show();
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="//cdn.feling.net/css/gitalk.css">
|
||||
<!-- <link rel="stylesheet" href="//cdn.feling.net/css/gitalk.css">
|
||||
<script src="//cdn.feling.net/js/gitalk.min.js"></script>
|
||||
<script>
|
||||
var gitalk = new Gitalk({
|
||||
|
@ -243,6 +243,6 @@ layout: default
|
|||
})
|
||||
|
||||
gitalk.render('gitalk-container')
|
||||
</script>
|
||||
</script> -->
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -393,7 +393,7 @@ soc.send(buf)
|
|||
|
||||
现在的程序还是多线程的模型,虽然功能已经实现。但是至少我自己在用的时候,明显感觉网速很慢。尤其是像腾讯、新浪这种门户网站的首页。一个页面的请求太他妈多了!!一下子就开了巨多的线程。线程相互之间切换的代价也是很大的,每个线程时间没做多少事,多数时间都在等待 IO。带宽没利用上多少,cpu 就快耗尽了,还都是耗在切换线程上,然后网速还很慢。
|
||||
|
||||
有一种叫协程的东西。内部好象是用 select poll epoll 那三个实现的。具体实现还没花时间研究过。它的效果大概是这样的:在一个线程里,有多个 socket,当一个 socket 在等待 IO 的时候,切换到其他的程序语句去执行。这个时候的切换,就相当于是函数调用的时候的切换,代价非常非常的小。用一个线程就能处理巨多的 socket ,充分利用 cpu 。
|
||||
有一种叫协程的东西。内部好象是用 select poll epoll 那三个实现的。具体实现还没花时间研究过([什么是epoll?](/pages/2023/01/select-epoll.html))。它的效果大概是这样的:在一个线程里,有多个 socket,当一个 socket 在等待 IO 的时候,切换到其他的程序语句去执行。这个时候的切换,就相当于是函数调用的时候的切换,代价非常非常的小。用一个线程就能处理巨多的 socket ,充分利用 cpu 。
|
||||
|
||||
实际用起来的效果,在代理运行在本地的时候,浏览器设置了代理,几乎感觉不到代理的存在。内存、cpu 等资源都占用得很少。部署到服务器上,带宽都耗尽了 cpu 资源都还剩余很多。
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
layout: pages
|
||||
title: 关于机械硬盘
|
||||
categories: 杂谈
|
||||
tags: [os, middleware, hdd]
|
||||
tags: [os, middleware, hdd, mq, mysql]
|
||||
---
|
||||
|
||||
|
||||
|
|
|
@ -204,6 +204,17 @@ ReentrantLock 还把 AQS 的 ConditionObject 暴露了出来,可以创建多
|
|||
|
||||
AQS.ConditionObject 类实现了 Condition 接口。每个 ConditionObject 里存着一条 Node 组成的等待队列。 ConditionObject 队列的 await()、signal() 方法,也已经由 AQS 模板实现好了。
|
||||
|
||||
|
||||
### CountDownLatch
|
||||
|
||||
CountDownLatch 对 AQS 的使用方式是这样的:
|
||||
|
||||
首先,在构造方法中,就把 state 设置成了 count。
|
||||
|
||||
然后,使用者调用 countDown() 实质是走到了 AQS.releaseShared() 去释放锁。CountDownLatch 通过 CAS 的操作对 state 的值减1。如果成功被减到了0,返回值才会是true,true 代表释放成功的含义,以触发 AQS.releaseShared() 去执行唤醒等待线程的操作。
|
||||
|
||||
最后,使用者调用 await() 实质是对应 AQS.acquireSharedInterruptibly() 去获取锁。CountDownLatch 判断如果 state == 0,就反馈给 AQS 获取锁成功,那么线程将直接继续运行。如果 state != 0,反馈给 AQS 获取锁失败,AQS 就会把线程阻塞,加入到等待队列。等待被上一小节中描述的 countDown() 操作唤醒。
|
||||
|
||||
## 展开讨论下CAS
|
||||
|
||||
### AtomicInteger
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: pages
|
||||
title:
|
||||
categories: 杂谈
|
||||
tags: [os, epoll]
|
||||
published: false
|
||||
---
|
||||
|
||||
|
||||
* 文章目录
|
||||
{:toc}
|
|
@ -1,11 +1,12 @@
|
|||
---
|
||||
layout: pages
|
||||
title:
|
||||
title: 关于MQ
|
||||
categories: 杂谈
|
||||
tags: [os, epoll]
|
||||
published: false
|
||||
---
|
||||
|
||||
|
||||
|
||||
* 文章目录
|
||||
{:toc}
|
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
layout: pages
|
||||
title: MySQL InnoDB 中的索引覆盖
|
||||
categories: 杂谈
|
||||
tags: [mysql]
|
||||
---
|
||||
|
||||
|
||||
## 什么是索引覆盖
|
||||
|
||||
新建一张表的时候,必须有一个主键。为什么必须呢?因为 InnoDB 存储引擎中,表里的数据就存在主键索引这颗B+树的叶子节点里。
|
||||
|
||||
而其他索引的叶子节点,存储的主要是主键id,是不包括这行的全量数据的。
|
||||
|
||||
使用普通索引查询数据的时候,走到叶子节点,也只能拿到 主键id 和 索引字段。还需要根据主键id再走一遍主键索引,才能拿到整行的数据。
|
||||
|
||||
什么是索引覆盖呢? 就是 select 的时候,如果只 select 主键id 和 当前查询使用的索引树对应的索引字段。就不需要回到主键索引里拿整行数据了。
|
||||
|
||||
## 错误的应用
|
||||
|
||||
经常在维护的代码里见到不用 `select *`,只 `select 具体字段` 的情况。 那些人是出于什么考虑,一个简单的星号不写,费劲去把字段一个个列出来呢?
|
||||
|
||||
也许是为了省带宽?
|
||||
|
||||
也许是觉得少几个字段能减少反序列化的开销?
|
||||
|
||||
也许最大的原因,是学到了 索引覆盖 这个知识点。就开始滥用了。。。
|
||||
|
||||
---
|
||||
|
||||
**我是推荐尽量使用 `select *` 的**。dao 层对外返回的数据,应该尽量是全量的。整体的模型,应该是越底层,越接近数据层,提供的数据字段越全面。越上层,越接近逻辑层、业务层,取用的字段越精细。
|
||||
|
||||
我们的业务在不断变化,需求在不停的提出。假如某天要给表增加一个字段。不用 select * 就得挨个 sql 改一遍。
|
||||
|
||||
更严重的情况不是给表增加字段。而是这个字段在表里原本就有,业务层原本没有使用。现在要用了,必然会出现直接在业务层代码里直接取用的操作,然而 dao 层根本没给返回值对象里设置这个字段的值。只能拿到null,等到自测、测试、甚至是上线后才发现。
|
||||
|
||||
---
|
||||
|
||||
在这个案例里,可维护性才是最重要的。真的不在乎那点计算资源的损耗。
|
||||
|
||||
|
||||
## 恰当应用的例子
|
||||
|
||||
使用 offset 关键字在 mysql 里执行分页操作。页数越大,性能越差。
|
||||
|
||||
什么原因呢?
|
||||
|
||||
跳出 mysql 的范畴,我们设计一个数据库的粗浅架构。可以分为 计算层 和 数据层。offset 的操作被划分在了计算层,数据层在执行 where 条件 筛选数据的时候并不知道哪些数据是该 offset 跳过的。
|
||||
|
||||
于是在查询 每页十条,第十页的数据 的时候,使用了 select *。数据层就只能查出一百条数据,并且一百条数据都需要回到主键索引去查出全量数据。走到主键索引的叶子节点这个步骤,大概率是要走磁盘IO的。一百条完整数据交给计算层后,才开始去做跳过前九页的操作。
|
||||
|
||||
mysql 不去做针对 offset 的优化。只能是我们使用者换个使用方式。把 sql 分成两条,第一条与原 sql 几乎一致,只把 select * 改成 select 主键id。第二条 sql 再根据 主键id 查全量数据。分两条 sql 操作,就避免了前九页数据的回主键索引走磁盘IO了。
|
||||
|
||||
如果要严守 sql 只 select * 的规范,可以把两条 sql 用子查询、join 的方式合并成一条。(这里是为了实现技术目的使用的join,并且join的驱动集非常小。尽量不要为了业务目的使用join。)
|
||||
|
||||
|
||||
## 针对 offset,推荐另一个方案
|
||||
|
||||
另一个处理 offset 问题的方案,是不用 sql 自带的 offset。由使用者增加一个 where 条件:(升序时) `where sort_field > 上一页最后一个 sort_field 的值`。
|
||||
|
||||
这也是变相的 “计算向数据转移”。把 offset 的计算转换成了 where 条件,where 条件是在数据层执行的。这个思想在大数据中常见。
|
||||
|
||||
说到大数据,假设 mysql 将来要平滑替换到 分布式的 TiDB。数据层肯定是分片的。类似于 mysql 中分表了,又没有分页规则,只能每张表都执行一遍。分页的场景下,要取 每页十条,第十页的数据,每个分片必须返回前一百条数据,才能保证拿到完整的第十页数据。把 offset 转换成 where 条件,每个分片就只需要各自的第十页数据就能拼出整体的第十页。
|
||||
|
||||
* 文章目录
|
||||
{:toc}
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
layout: pages
|
||||
title: select、epoll
|
||||
categories: 杂谈
|
||||
tags: [os, epoll]
|
||||
---
|
||||
|
||||
讲网络IO模型,先区分下两个层级,一是操作系统层,二是我们的用户代码层。
|
||||
|
||||
一切都依赖于操作系统的内核代码的发展,
|
||||
|
||||
## BIO
|
||||
|
||||
早期,操作系统只提供阻塞式的系统调用。用户代码也就只好用 “来一个socket连接,就为它单独起一个线程来接收数据” 的线程模型。不单独分配线程的话,程序阻塞在那,一次就只能处理一个请求。这个阶段最突出的问题,在于大量线程的创建、回收、切换的损耗。
|
||||
|
||||
## NIO
|
||||
|
||||
后来发展出了非阻塞的系统调用。也就是 accept() 方法会立即返回了,只不过没有连接的时候返回的是null。recv() 也支持立即返回,可以去询问某个连接是不是可以读数据了。这解决了大量线程的创建、回收、切换的问题。用户程序可以在一个线程里循环 accept(),不是null就放到列表里存起来。甚至再拮据一点,就在这段循环里把列表里的连接挨个拿到操作系统那边询问,是不是可以读数据了。一个线程可以维护多个连接了。这个阶段最突出的问题,在于大量向操作系统询问连接是否可用的操作,系统调用的消耗极大,又只有少数的询问能得到肯定回复。
|
||||
|
||||
## NIO 中的多路复用器
|
||||
|
||||
再后来,多路复用器出现了,select() 支持一次传多个连接做参数,虽然还是需要挨个连接判断一遍,但这个遍历过程全程在内核态完成。减少了系统调用的次数。这个阶段最突出的问题,在于内核内部依然需要遍历所有连接。poll() 这个多路复用器会更新一点,但它的实现也是需要遍历所有连接。
|
||||
|
||||
## 多路复用器的更新
|
||||
|
||||
再后来,多路复用器出了一个新的版本,叫 epoll。
|
||||
|
||||
epoll_create() 创建一个实例,
|
||||
|
||||
epoll_ctl() 往里添加要监控的连接,
|
||||
|
||||
epoll_wait() 去询问有没有可读的连接。
|
||||
|
||||
比起 select() 的直接询问,epoll 的调用方式多了创建实例和添加被监控连接这两个前置步骤。在前置的步骤里,它需要给这个epoll实例分配一颗红黑树和一个列表,把连接放进树里。当网卡的中断来临,select 需要的只是有人能把连接状态标记为可以读数据就行了。而 epoll 还多了一步,维护红黑树的节点,把这个可读的连接移动到专门的列表里。用户程序来询问的时候,直接查看可读列表的数据,不需要遍历所有节点了。
|
||||
|
||||
## New IO 还是 Non-Blocking IO ?
|
||||
|
||||
NIO 这个词,操作系统里叫 Non-Blocking IO,指的是提供了一套非阻塞的系统调用。java 里叫 New IO,它伴随着操作系统网络IO的发展,新封装了操作系统的调用,装成统一的java的 Selector类,底下实际用的是select 还是 epoll,又或者是windows才有的其他多路复用器,要看操作系统的支持。
|
||||
|
||||
* 文章目录
|
||||
{:toc}
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
layout: pages
|
||||
title: 读 CopyOnWriteArrayList
|
||||
categories: [Java]
|
||||
---
|
||||
|
||||
随机挑一个java类来读,今天读的是 JUC 下的 CopyOnWriteArrayList。
|
||||
|
||||
## 线程安全 与 CopyOnWrite
|
||||
|
||||
CopyOnWrite 是保证线程安全的一个常用手段,这让我联想到刚接触 guava 的时候,大多数被传说是线程安全的类,在修改的时候都是返回了一个新的对象。
|
||||
|
||||
比如 Splitter:
|
||||
|
||||
```java
|
||||
// 使用
|
||||
Splitter splitter = Splitter.on("|").omitEmptyStrings();
|
||||
|
||||
// omitEmptyStrings() 源码
|
||||
public Splitter omitEmptyStrings() {
|
||||
return new Splitter(strategy, true, trimmer, limit); // 第二个参数对应 omitEmptyStrings = true
|
||||
}
|
||||
```
|
||||
|
||||
在设置是否忽略空白字符串的时候,返回了新的对象。使用的是不同的对象,自然就不存在线程的安全的问题。
|
||||
|
||||
## 主要作用于 iterator
|
||||
|
||||
CopyOnWriteArrayList 中的 CopyOnWrite,主要作用发挥在遍历的操作。让遍历操作是基于快照的方式进行,不会有遍历时修改数据的问题,不需要做线程同步的操作。
|
||||
|
||||
```java
|
||||
// CopyOnWriteArrayList.iterator() 方法
|
||||
public Iterator<E> iterator() {
|
||||
return new COWIterator<E>(getArray(), 0); // 是一个自定义的特殊 Iterator: COWIterator
|
||||
}
|
||||
|
||||
// COWIterator 构造方法
|
||||
private COWIterator(Object[] elements, int initialCursor) {
|
||||
cursor = initialCursor;
|
||||
snapshot = elements; // 取得快照
|
||||
}
|
||||
```
|
||||
|
||||
iterator 对象拿到的只是快照,所以这必须是个特殊的 iterator。iterator.remove()、iterator.set(E e)、iterator.add(E e) 都是 UnsupportedOperation。因为修改的操作没办法影响到当前实际列表。
|
||||
|
||||
|
||||
## 要完整的线程安全,还是需要加锁的
|
||||
|
||||
CopyOnWrite 对 List 的 add() 之类的操作其实是不友好的。每次都创建新的,代价是很大的。
|
||||
|
||||
而且因为 Copy、 Write、Replace 的操作都不是原子操作,CopyOnWrite 本身是不可能保证 add() 的线程安全的。所有的修改操作,都还是要加锁。CopyOnWriteArrayList 有个 ReentrantLock 成员变量,所有的写操作都加锁了。
|
||||
|
||||
|
||||
## synchronizedList
|
||||
|
||||
到目前为止,是否选用这个类,判断依据就很明显了。重遍历 的场景下适合用。
|
||||
|
||||
如果是 重修改 的场景该用哪个类呢?怎么找?回到 ArrayList 类里面,这种注意事项级别的问题,通常 jdk 的开发者都会把答案写在基础类的注释里的。
|
||||
|
||||
看下注释就得到了 `Collections.synchronizedList` 这个答案,并且也有 synchronizedList 在遍历方面存在各种问题的描述。
|
||||
|
||||
## ArrayList
|
||||
|
||||
顺带看下 ArrayList
|
||||
|
||||
1. 默认容量是10
|
||||
2. add 的时候。先做扩容相关的确认,再设置数据
|
||||
3. 容量完全使用光的时候才扩容。这点和 Map 的有小于1的负荷系数不一样,Map 的填充是一个概率问题。但是 Array 的填充是明确的。
|
||||
4. 新的容量取的是 new = old + (old >> 1),也就是原来的 1.5 倍。
|
||||
|
||||
(有个神奇的 MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8,为啥 -8 呢...答案就在源码注释里 →.→)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
* 文章目录
|
||||
{:toc}
|
|
@ -0,0 +1,81 @@
|
|||
---
|
||||
layout: pages
|
||||
title: 读 HashSet(读 HashMap)
|
||||
categories: [Java]
|
||||
---
|
||||
|
||||
随机挑一个java类来读,今天读的是 HashSet。
|
||||
|
||||
HashSet 就是 HashMap 的 key。。。就。。。读完了。。。
|
||||
|
||||
得改个题目,读 HashMap。
|
||||
|
||||
## 翻译下 HashMap 类的注释
|
||||
|
||||
基于散列表实现的 Map 接口。实现了所有可选的 map 操作,并且允许 null 值 和 null key。大体上和 Hashtable 功能类似,除了 HashMap 不是线程同步的,并且允许 null。这个类不保证顺序,甚至不保证已有的元素顺序的可重复读。
|
||||
|
||||
假设散列函数能恰当地把元素分散到哈希桶里,那么对于基础的操作,比如 get() 和 put(),能提供 O(1) 的时间复杂度. 对于集合视图的遍历所需要的时间,跟其 “容量” (桶的数量)加上其大小(内含键值对的数量)成正比。所以如果遍历的性能比较重要,就不要把初始容量设置得太大,或者把触发扩容用的负载系数设置得太低。
|
||||
|
||||
一个 HashMap 的实例,有两个影响性能的参数:初始容量(initial capacity) 和 负载系数(load factor)
|
||||
|
||||
原文逐字翻译的话,废话太多了,接下来用自己的话说吧。。load factor 描述了哈希表有多满,是判断哈希表是否需要扩容的标准,当 键值对的数量 > load factor 乘以 HashMap 的容量,就会自动扩容,容量翻倍,这个操作需要对数据进行 rehash。
|
||||
|
||||
load factor 默认 0.75,是权衡的结果,较高的值减少了空间开销,但增加了查找成本(影响绝大部分的操作,包括 get 和 put)。在设置初始容量时,应考虑预期条目数量及其负载系数,以尽量减少 rehash 操作的次数。如果初始容量大于最大条目数除以负载系数,则不会发生 rehash。
|
||||
|
||||
如果预期要存储的条目数比较大,一开始就设置一个大的初始容量,比让它自动 rehash 并扩容要好得多。
|
||||
|
||||
如果大部分条目的 hashCode 是相同的(也就是hash冲突比较多),会大大降低哈希表的性能。所以如果 key 是 Comparable 的类,也会结合他们比大小的结果。(这句就有点不太理解了)
|
||||
|
||||
要注意它的是非同步的。多线程使用时必须自己外加同步操作。或者直接用 Collections.synchronizedMap 包一层。
|
||||
|
||||
|
||||
除非用 iterator 对象下自带的 remove 方法,不然的话,在通过 iterator 遍历期间,如果对 Map 进行了结构修改,iterator 会尽可能快速失败,立即报错的。(总之就是说一边遍历,一边并发的修改 是很奇葩的操作。我是建议试下搞个快照出来遍历)
|
||||
|
||||
---
|
||||
|
||||
抽几个关键词出来:
|
||||
|
||||
允许null、
|
||||
|
||||
初始容量、
|
||||
|
||||
负载系数、
|
||||
|
||||
非同步的操作、
|
||||
|
||||
不要遍历时并发修改、
|
||||
|
||||
下面开始看代码了。。。希望能发现一些新东西。。。还有最初的目的 "keySet" 呀。。。
|
||||
|
||||
## 解决哈希冲突
|
||||
|
||||
一个桶里要对应多个元素。数量少的时候是链表。达到 TREEIFY_THRESHOLD = 8 个元素且容量大于64时,转换成树结构。6个元素时,变回链表。桶里存的是链表或树的根节点。
|
||||
|
||||
## HashSet
|
||||
|
||||
HashSet 就是 HashMap 的 keySet。那么 key 的值都存在哪里?集合内元素不可以重复这个特性怎么得来的?
|
||||
|
||||
key 跟 value 一起打包成了 Node 对象。Node 存到了哈希表里。
|
||||
|
||||
要拿到 keySet 里所有的 key 的值,只能从哈希表里遍历额。HashIterator 会有一些遍历到空白桶位的额外消耗。
|
||||
|
||||
好处是 Set 的集合内元素不可以重复这个特性,可以直接从哈希表传承到一大部分,再从处理哈希冲突的数据结构里传承到剩下的部分。
|
||||
|
||||
## 扩容
|
||||
|
||||
容量翻倍
|
||||
|
||||
```java
|
||||
newCap = oldCap << 1
|
||||
```
|
||||
|
||||
## containsValue() 性能有点惨
|
||||
|
||||
``` java
|
||||
for(哈希桶)
|
||||
for(单个桶里所有元素)
|
||||
```
|
||||
|
||||
|
||||
* 文章目录
|
||||
{:toc}
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
layout: pages
|
||||
title: 读 类加载器
|
||||
categories: [Java]
|
||||
published: false
|
||||
|
||||
---
|
||||
|
||||
挑一个java类来读,今天读的是 sun.misc.Launcher
|
||||
|
||||
为啥会看到这个类?因为复习到了 java 的类加载机制,点进去看 ClassLoader 的源码,追溯到了这个类。
|
||||
|
||||
## 双亲委派
|
||||
|
||||
## 双亲委派模型的破坏
|
||||
|
||||
## 单例模式
|
||||
|
||||
## 基于类加载实现的单例,实质都是用的 synchronized
|
||||
|
||||
|
||||
* 文章目录
|
||||
{:toc}
|
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
layout: pages
|
||||
title: ArrayBlockingQueue
|
||||
categories: [Java]
|
||||
|
||||
---
|
||||
|
||||
ArrayBlockingQueue,闭着眼睛自己构思一个,用不着翻 jdk 的源码。
|
||||
|
||||
要用数组实现一个阻塞队列。可以拆出三个部分分别讨论。
|
||||
|
||||
1. 队列
|
||||
2. 阻塞
|
||||
3. 并发
|
||||
|
||||
## 队列
|
||||
|
||||
首先需要一个数组来存储队列中的数据。
|
||||
|
||||
然后讨论先进先出的特性如何实现,我们需要两个标记,分别记录入队的数据要添加到数组的哪个位置、出队的数据要从哪个位置取。这两个标记都从0下标开始往后走。
|
||||
|
||||
这就出现了一个问题,标记指向的位置不停的往前走,数组不可能为了它无限延长。就需要在逻辑上把数组看成一个环。假设队列容量是12,标志到11后再往前走一格就该变到0了。
|
||||
|
||||
注意限制出队标志不能走到入队标志前面去。
|
||||
|
||||
|
||||
|
||||
## 阻塞
|
||||
|
||||
用 ReentrantLock 建两个 Condition 出来。一个用来队列满时阻塞生产者,一个用来队列空时阻塞消费者。在数据入队的时候去唤醒消费者,数据出队的时候去唤醒生产者。
|
||||
|
||||
## 并发
|
||||
|
||||
修改数组数据的操作,都用 ReentrantLock 加一下锁。
|
||||
|
||||
|
||||
|
||||
|
||||
* 文章目录
|
||||
{:toc}
|
|
@ -85,6 +85,12 @@
|
|||
<hr style="margin:0">
|
||||
<p style="text-align:left;font-size:11px;margin:0px;">格式化、高亮、折叠你的 json 字符串</p>
|
||||
</a>
|
||||
|
||||
<a class="uk-button" style="margin: 0px 0px 10px 10px;" href="/jwt/">
|
||||
<div style="text-align:left;font-size:18px">JWT 解码</div>
|
||||
<hr style="margin:0">
|
||||
<p style="text-align:left;font-size:11px;margin:0px;">JSON Web Token 在线解码</p>
|
||||
</a>
|
||||
|
||||
<a class="uk-button" style="margin: 0px 0px 10px 10px;" href="/base64/"
|
||||
onclick="localStorage.base64_activeTab = 1;">
|
||||
|
@ -228,6 +234,7 @@
|
|||
<li><a href="/pages/base64.html">理解 Base64 编码</a></li>
|
||||
<li><a href="/pages/rank_tip.html">垃圾页面提示</a></li>
|
||||
<li><a href="/404.html">404页面提示</a></li>
|
||||
<li><a href="/proxy.pac">pac配置</a></li>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -238,7 +245,7 @@
|
|||
开源地址: https://gitee.com/apihub/feling.net
|
||||
</span><br><br>
|
||||
<span>
|
||||
<a href="http://www.beian.miit.gov.cn" rel="nofollow">闽ICP备19012687号</a>
|
||||
<a href="http://beian.miit.gov.cn" rel="nofollow">闽ICP备17033777号</a>
|
||||
</span><br><br>
|
||||
<br>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,350 @@
|
|||
---
|
||||
title: JWT 解码
|
||||
layout: default_tool
|
||||
keywords: [jwt, JSON Web Token, jwt在线解码]
|
||||
description: jwt 在线解码工具
|
||||
---
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
.json_key {
|
||||
color: #92278f;
|
||||
font-weight: bold;
|
||||
}
|
||||
.json_string {
|
||||
color: #3ab54a;
|
||||
font-weight: bold;
|
||||
}
|
||||
.json_link {
|
||||
color: #61D2D6;
|
||||
font-weight: bold;
|
||||
text-decoration:none;
|
||||
}
|
||||
.json_link:hover {
|
||||
color: #005599;
|
||||
font-weight: bold;
|
||||
text-decoration:none;
|
||||
}
|
||||
.json_number {
|
||||
color: #25aae2;
|
||||
font-weight: bold;
|
||||
}
|
||||
.json_boolean {
|
||||
color: #f98280;
|
||||
font-weight: bold;
|
||||
}
|
||||
.json_null {
|
||||
color: #ccc;
|
||||
font-weight: bold;
|
||||
}
|
||||
.fold_icon{
|
||||
font-size: 12px;
|
||||
color: #ccc;
|
||||
}
|
||||
#json_src {
|
||||
word-break: break-all;
|
||||
height: 100%;
|
||||
resize: vertical;
|
||||
padding: 10px;
|
||||
font-size: 13px;
|
||||
font-family: Consolas, monospace;
|
||||
}
|
||||
#json_result {
|
||||
font-family: Consolas, monospace;
|
||||
}
|
||||
@media (min-width: 960px) {
|
||||
#content {
|
||||
display: flex;
|
||||
}
|
||||
#json_src_box {
|
||||
width: 38%;
|
||||
}
|
||||
#json_result_box {
|
||||
padding-left: 10px;
|
||||
width: 62%;
|
||||
}
|
||||
}
|
||||
@media (max-width: 960px) {
|
||||
#json_src_box {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
#json_result_box {
|
||||
margin-top: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
if (!String.prototype.repeat) {
|
||||
String.prototype.repeat = function(count) {
|
||||
'use strict';
|
||||
if (this == null)
|
||||
throw new TypeError('can\'t convert ' + this + ' to object');
|
||||
|
||||
var str = '' + this;
|
||||
// To convert string to integer.
|
||||
count = +count;
|
||||
// Check NaN
|
||||
if (count != count)
|
||||
count = 0;
|
||||
|
||||
if (count < 0)
|
||||
throw new RangeError('repeat count must be non-negative');
|
||||
|
||||
if (count == Infinity)
|
||||
throw new RangeError('repeat count must be less than infinity');
|
||||
|
||||
count = Math.floor(count);
|
||||
if (str.length == 0 || count == 0)
|
||||
return '';
|
||||
|
||||
// Ensuring count is a 31-bit integer allows us to heavily optimize the
|
||||
// main part. But anyway, most current (August 2014) browsers can't handle
|
||||
// strings 1 << 28 chars or longer, so:
|
||||
if (str.length * count >= 1 << 28)
|
||||
throw new RangeError('repeat count must not overflow maximum string size');
|
||||
|
||||
var maxCount = str.length * count;
|
||||
count = Math.floor(Math.log(count) / Math.log(2));
|
||||
while (count) {
|
||||
str += str;
|
||||
count--;
|
||||
}
|
||||
str += str.substring(0, maxCount - str.length);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
if (!String.prototype.startsWith) {
|
||||
Object.defineProperty(String.prototype, 'startsWith', {
|
||||
value: function(search, pos) {
|
||||
pos = !pos || pos < 0 ? 0 : +pos;
|
||||
return this.substring(pos, pos + search.length) === search;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!String.prototype.endsWith) {
|
||||
String.prototype.endsWith = function(search, this_len) {
|
||||
if (this_len === undefined || this_len > this.length) {
|
||||
this_len = this.length;
|
||||
}
|
||||
return this.substring(this_len - search.length, this_len) === search;
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<div id="content">
|
||||
|
||||
|
||||
<div id="json_src_box" class="uk-width-10-10">
|
||||
<textarea id="json_src" class="uk-width-1-1" autofocus spellcheck="false" v-model="jsonSrc"
|
||||
v-on:click="$('#cursor-position').show();cursorPosition = $('#json_src').prop('selectionStart')"
|
||||
v-on:keydown="cursorPosition = $('#json_src').prop('selectionStart')"
|
||||
v-on:blur="cursorPosition = '?'"
|
||||
v-on:input="cursorPosition = $('#json_src').prop('selectionStart');jsonSrcChange()">
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
<div id="json_result_box" class="uk-width-10-10" style="overflow: auto;">
|
||||
<div class="uk-width-1-1">
|
||||
<pre style="margin:0;"><code v-html="jsonResult_header" id="json_result_header"></code></pre>
|
||||
</div>
|
||||
|
||||
<div class="uk-width-1-1" style="margin-top: 10px;">
|
||||
<pre style="margin:0;"><code v-html="jsonResult" id="json_result"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(global){"use strict";var _Base64=global.Base64;var version="2.3.2";var buffer;if(typeof module!=="undefined"&&module.exports){try{buffer=require("buffer").Buffer}catch(err){}}var b64chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var b64tab=function(bin){var t={};for(var i=0,l=bin.length;i<l;i++)t[bin.charAt(i)]=i;return t}(b64chars);var fromCharCode=String.fromCharCode;var cb_utob=function(c){if(c.length<2){var cc=c.charCodeAt(0);return cc<128?c:cc<2048?fromCharCode(192|cc>>>6)+fromCharCode(128|cc&63):fromCharCode(224|cc>>>12&15)+fromCharCode(128|cc>>>6&63)+fromCharCode(128|cc&63)}else{var cc=65536+(c.charCodeAt(0)-55296)*1024+(c.charCodeAt(1)-56320);return fromCharCode(240|cc>>>18&7)+fromCharCode(128|cc>>>12&63)+fromCharCode(128|cc>>>6&63)+fromCharCode(128|cc&63)}};var re_utob=/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;var utob=function(u){return u.replace(re_utob,cb_utob)};var cb_encode=function(ccc){var padlen=[0,2,1][ccc.length%3],ord=ccc.charCodeAt(0)<<16|(ccc.length>1?ccc.charCodeAt(1):0)<<8|(ccc.length>2?ccc.charCodeAt(2):0),chars=[b64chars.charAt(ord>>>18),b64chars.charAt(ord>>>12&63),padlen>=2?"=":b64chars.charAt(ord>>>6&63),padlen>=1?"=":b64chars.charAt(ord&63)];return chars.join("")};var btoa=global.btoa?function(b){return global.btoa(b)}:function(b){return b.replace(/[\s\S]{1,3}/g,cb_encode)};var _encode=buffer?buffer.from&&buffer.from!==Uint8Array.from?function(u){return(u.constructor===buffer.constructor?u:buffer.from(u)).toString("base64")}:function(u){return(u.constructor===buffer.constructor?u:new buffer(u)).toString("base64")}:function(u){return btoa(utob(u))};var encode=function(u,urisafe){return!urisafe?_encode(String(u)):_encode(String(u)).replace(/[+\/]/g,function(m0){return m0=="+"?"-":"_"}).replace(/=/g,"")};var encodeURI=function(u){return encode(u,true)};var re_btou=new RegExp(["[À-ß][-¿]","[à-ï][-¿]{2}","[ð-÷][-¿]{3}"].join("|"),"g");var cb_btou=function(cccc){switch(cccc.length){case 4:var cp=(7&cccc.charCodeAt(0))<<18|(63&cccc.charCodeAt(1))<<12|(63&cccc.charCodeAt(2))<<6|63&cccc.charCodeAt(3),offset=cp-65536;return fromCharCode((offset>>>10)+55296)+fromCharCode((offset&1023)+56320);case 3:return fromCharCode((15&cccc.charCodeAt(0))<<12|(63&cccc.charCodeAt(1))<<6|63&cccc.charCodeAt(2));default:return fromCharCode((31&cccc.charCodeAt(0))<<6|63&cccc.charCodeAt(1))}};var btou=function(b){return b.replace(re_btou,cb_btou)};var cb_decode=function(cccc){var len=cccc.length,padlen=len%4,n=(len>0?b64tab[cccc.charAt(0)]<<18:0)|(len>1?b64tab[cccc.charAt(1)]<<12:0)|(len>2?b64tab[cccc.charAt(2)]<<6:0)|(len>3?b64tab[cccc.charAt(3)]:0),chars=[fromCharCode(n>>>16),fromCharCode(n>>>8&255),fromCharCode(n&255)];chars.length-=[0,0,2,1][padlen];return chars.join("")};var atob=global.atob?function(a){return global.atob(a)}:function(a){return a.replace(/[\s\S]{1,4}/g,cb_decode)};var _decode=buffer?buffer.from&&buffer.from!==Uint8Array.from?function(a){return(a.constructor===buffer.constructor?a:buffer.from(a,"base64")).toString()}:function(a){return(a.constructor===buffer.constructor?a:new buffer(a,"base64")).toString()}:function(a){return btou(atob(a))};var decode=function(a){return _decode(String(a).replace(/[-_]/g,function(m0){return m0=="-"?"+":"/"}).replace(/[^A-Za-z0-9\+\/]/g,""))};var noConflict=function(){var Base64=global.Base64;global.Base64=_Base64;return Base64};global.Base64={VERSION:version,atob:atob,btoa:btoa,fromBase64:decode,toBase64:encode,utob:utob,encode:encode,encodeURI:encodeURI,btou:btou,decode:decode,noConflict:noConflict};if(typeof Object.defineProperty==="function"){var noEnum=function(v){return{value:v,enumerable:false,writable:true,configurable:true}};global.Base64.extendString=function(){Object.defineProperty(String.prototype,"fromBase64",noEnum(function(){return decode(this)}));Object.defineProperty(String.prototype,"toBase64",noEnum(function(urisafe){return encode(this,urisafe)}));Object.defineProperty(String.prototype,"toBase64URI",noEnum(function(){return encode(this,true)}))}}if(global["Meteor"]){Base64=global.Base64}if(typeof module!=="undefined"&&module.exports){module.exports.Base64=global.Base64}else if(typeof define==="function"&&define.amd){define([],function(){return global.Base64})}})(typeof self!=="undefined"?self:typeof window!=="undefined"?window:typeof global!=="undefined"?global:this);
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function hideIcon() {
|
||||
$('.uk-icon-angle-right').hide();
|
||||
$('.uk-icon-angle-down').hide();
|
||||
}
|
||||
function showIcon() {
|
||||
$('.uk-icon-angle-right').show();
|
||||
$('.uk-icon-angle-down').show();
|
||||
}
|
||||
function fold(icon) {
|
||||
icon.classList.remove('uk-icon-angle-down')
|
||||
icon.classList.add('uk-icon-angle-right')
|
||||
icon.setAttribute('onClick', 'javascript: unFold(this)')
|
||||
icon.childNodes[0].style.display = 'inline'
|
||||
icon.nextSibling.style.display = 'none'
|
||||
}
|
||||
function unFold(icon) {
|
||||
icon.classList.remove('uk-icon-angle-right')
|
||||
icon.classList.add('uk-icon-angle-down')
|
||||
icon.setAttribute('onClick', 'javascript: fold(this)')
|
||||
icon.childNodes[0].style.display = 'none'
|
||||
icon.nextSibling.style.display = 'inline'
|
||||
}
|
||||
var vm = new Vue({
|
||||
el: "#content",
|
||||
data: {
|
||||
reLink: /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig,
|
||||
cursorPosition: '?',
|
||||
jsonSrc: ``,
|
||||
jsonResultTemp:[],
|
||||
jsonObject: undefined,
|
||||
jsonResult_header: '',
|
||||
jsonResult: '',
|
||||
tab: ' ',
|
||||
keyEnd: '"</span>: '
|
||||
},
|
||||
mounted: function () {
|
||||
if (localStorage.jwt_jsonSrc) {
|
||||
this.jsonSrc = localStorage.jwt_jsonSrc
|
||||
}
|
||||
this.jsonSrcChange()
|
||||
|
||||
},
|
||||
methods: {
|
||||
isArray: function (obj) {
|
||||
return obj && typeof obj === 'object' && typeof obj.length === 'number' && !(obj.propertyIsEnumerable('length'))
|
||||
},
|
||||
jsonLinkWarpper: function (str) {
|
||||
return str.replace(this.reLink, '<a class="json_link" target="_blank" href="$1">$1</a>');
|
||||
},
|
||||
genKey: function (key, depth) {
|
||||
this.jsonResultTemp.push("<br><span class='json_key'>")
|
||||
this.jsonResultTemp.push(this.tab.repeat(depth + 1))
|
||||
this.jsonResultTemp.push("\"")
|
||||
this.jsonResultTemp.push($('<div/>').text(key).html())
|
||||
this.jsonResultTemp.push(this.keyEnd)
|
||||
},
|
||||
genValue: function (obj, depth) {
|
||||
if (!this.jsonResultTemp[this.jsonResultTemp.length - 1].endsWith(this.keyEnd)) { // 冒号后面不换行
|
||||
this.jsonResultTemp.push('<br>')
|
||||
this.jsonResultTemp.push(this.tab.repeat(depth))
|
||||
}
|
||||
var type = obj === null ? 'null' : typeof obj
|
||||
this.jsonResultTemp.push('<span class="json_')
|
||||
this.jsonResultTemp.push(type)
|
||||
this.jsonResultTemp.push('">')
|
||||
if (type === 'string') {
|
||||
this.jsonResultTemp.push('"')
|
||||
this.jsonResultTemp.push(this.jsonLinkWarpper($('<div/>').text(obj === null ? 'null' : obj).html()))
|
||||
this.jsonResultTemp.push('"')
|
||||
} else {
|
||||
this.jsonResultTemp.push(obj === null ? 'null' : obj)
|
||||
}
|
||||
this.jsonResultTemp.push('</span>,')
|
||||
},
|
||||
genStart: function (start, depth, itemCount) {
|
||||
if (this.jsonResultTemp.length > 0
|
||||
&& !this.jsonResultTemp[this.jsonResultTemp.length - 1].endsWith(this.keyEnd)) { // 冒号后面不换行
|
||||
this.jsonResultTemp.push('<br>')
|
||||
this.jsonResultTemp.push(this.tab.repeat(depth))
|
||||
}
|
||||
this.jsonResultTemp.push(start)
|
||||
if (depth > this.defaultFold || itemCount === 0) {
|
||||
this.jsonResultTemp.push('<i class="uk-icon-angle-right" onClick="unFold(this)">'
|
||||
+ '<span class="fold_icon">...' + itemCount + '</span>'
|
||||
+ '</i>'
|
||||
+ '<span class="foldContent" style="display:none">')
|
||||
} else {
|
||||
this.jsonResultTemp.push('<i class="uk-icon-angle-down" onClick="fold(this)">'
|
||||
+ '<span class="fold_icon" style="display:none;">...' + itemCount + '</span>'
|
||||
+ '</i>'
|
||||
+ '<span class="foldContent">')
|
||||
}
|
||||
},
|
||||
genEnd: function (end, depth) {
|
||||
this.deletLastComma()
|
||||
this.jsonResultTemp.push('<br>')
|
||||
this.jsonResultTemp.push(this.tab.repeat(depth))
|
||||
|
||||
this.jsonResultTemp.push('</span>') // <span class="foldContent">
|
||||
this.jsonResultTemp.push(end)
|
||||
this.jsonResultTemp.push(',')
|
||||
},
|
||||
deletLastComma: function () {
|
||||
var old = this.jsonResultTemp.pop()
|
||||
var index = old.lastIndexOf(',')
|
||||
var index1 = old.lastIndexOf('{')
|
||||
var index2 = old.lastIndexOf('[')
|
||||
if (index > index1 && index > index2) {
|
||||
this.jsonResultTemp.push(old.substring(0, index))
|
||||
this.jsonResultTemp.push(old.substring(index + 1))
|
||||
return true
|
||||
}
|
||||
this.jsonResultTemp.push(old)
|
||||
return false
|
||||
},
|
||||
genResult: function (obj, depth) {
|
||||
if (this.isArray(obj)) {
|
||||
this.genStart('[', depth, obj.length)
|
||||
for(var i = 0; i < (this.arraySampling ? Math.min(obj.length, 1) : obj.length); i++) {
|
||||
this.genResult(obj[i], depth + 1)
|
||||
}
|
||||
this.genEnd(']', depth)
|
||||
return
|
||||
}
|
||||
if ((typeof obj) === 'object' && obj !== null) {
|
||||
this.genStart('{', depth, Object.keys(obj).length)
|
||||
for (key in obj) {
|
||||
this.genKey(key, depth)
|
||||
this.genResult(obj[key], depth + 1)
|
||||
}
|
||||
this.genEnd('}', depth)
|
||||
return
|
||||
}
|
||||
this.genValue(obj, depth)
|
||||
},
|
||||
jsonSrcChange: function () {
|
||||
if (this.jsonSrc === '') {
|
||||
return
|
||||
}
|
||||
try {
|
||||
jwtSrc = this.jsonSrc.replace("Bearer ", "").split(".")
|
||||
this.jsonObject = JSON.parse(Base64.decode(jwtSrc[0]))
|
||||
this.jsonResultTemp = []
|
||||
this.genResult(this.jsonObject, 0)
|
||||
this.deletLastComma()
|
||||
this.jsonResult_header = this.jsonResultTemp.join("")
|
||||
|
||||
this.jsonObject = JSON.parse(Base64.decode(jwtSrc[1]))
|
||||
this.jsonResultTemp = []
|
||||
this.genResult(this.jsonObject, 0)
|
||||
this.deletLastComma()
|
||||
this.jsonResult = this.jsonResultTemp.join("")
|
||||
|
||||
localStorage.jwt_jsonSrc = this.jsonSrc
|
||||
} catch (e) {
|
||||
this.jsonResult_header = ''
|
||||
this.jsonResult = e.message
|
||||
}
|
||||
},
|
||||
traverseChildren: function (element, func, depth) {
|
||||
for(var i = 0; i < element.childNodes.length; i++){
|
||||
this.traverseChildren(element.childNodes[i], func, depth + 1)
|
||||
}
|
||||
func(element, depth)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
$('#json_result_box').scroll(function() {
|
||||
if ($('#json_result_box').scrollTop() > 400)
|
||||
$('div.go-top').show();
|
||||
else
|
||||
$('div.go-top').hide();
|
||||
});
|
||||
$('div.go-top').click(function() {
|
||||
$('#json_result_box').animate({scrollTop: 0}, 400);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
// var proxy = "PROXY localhost:7890";
|
||||
var proxy = "SOCKS5 localhost:7890";
|
||||
|
||||
function FindProxyForURL(url, host) {
|
||||
if (shExpMatch(host,"*qunar*")
|
||||
|| shExpMatch(host,"*.cn")
|
||||
|| shExpMatch(host,"*baidu*")
|
||||
|| shExpMatch(host,"*bdstatic*")
|
||||
|| shExpMatch(host,"*aliyun*")
|
||||
|| shExpMatch(host,"*alicdn*")
|
||||
|| shExpMatch(host,"*mmstat*")
|
||||
|| shExpMatch(host,"*alipay*")
|
||||
|| shExpMatch(host,"*99.com")
|
||||
|| shExpMatch(host,"*.qq.com")
|
||||
|| shExpMatch(host,"*.99.com")
|
||||
|| shExpMatch(host,"101.com")
|
||||
|| shExpMatch(host,"*.101.com")
|
||||
|| shExpMatch(host,"*.sdp")
|
||||
|| shExpMatch(host,"*.nd")
|
||||
|| shExpMatch(host,"*.ndaeweb.com")
|
||||
|| shExpMatch(host,"*.hdslb.com")
|
||||
) {
|
||||
return "DIRECT";
|
||||
}
|
||||
|
||||
if (shExpMatch(host,"*google*")
|
||||
|| shExpMatch(host,"*chrome*")
|
||||
|| shExpMatch(host,"*gstatic*")
|
||||
|| shExpMatch(host,"*youtube*")
|
||||
|| shExpMatch(host,"*ytimg*")
|
||||
|| shExpMatch(host,"*ggpht*")
|
||||
|| shExpMatch(host,"*facebook*")
|
||||
|| shExpMatch(host,"*fbcdn*")
|
||||
|| shExpMatch(host,"*twitter*")
|
||||
|| shExpMatch(host,"*twimg*")
|
||||
|| shExpMatch(host,"*gist*")
|
||||
|| shExpMatch(host,"*github*")
|
||||
|| shExpMatch(host,"*wikipedia*")
|
||||
|| shExpMatch(host,"*stackoverflow*")
|
||||
|| shExpMatch(host,"*wikimedia*")
|
||||
|| shExpMatch(host,"*xvideos*")
|
||||
|| shExpMatch(host,"*porn*")
|
||||
|| shExpMatch(host,"*.phncdn.com")
|
||||
|| shExpMatch(host,"*.trafficjunky.net")
|
||||
|| shExpMatch(host,"*sis001*")
|
||||
|| shExpMatch(host,"*rubygems*")
|
||||
|| shExpMatch(host,"*weather*")
|
||||
|| shExpMatch(host,"*amazonaws*")
|
||||
|| shExpMatch(host,"*doubleclick.net")
|
||||
|| shExpMatch(host,"*.doubleclick.net")
|
||||
|| shExpMatch(host,"*cloudfront.net")
|
||||
|| shExpMatch(host,"*shadowsocks.com")
|
||||
|| shExpMatch(host,"*.io")
|
||||
|| shExpMatch(host,"*.binance.com")
|
||||
|| shExpMatch(host,"*.bnbstatic.com")
|
||||
|| shExpMatch(host,"ntotheblock.com")
|
||||
|| shExpMatch(host,"disqus.com")
|
||||
|| shExpMatch(host,"*.disqus.com")
|
||||
) {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
return "DIRECT";
|
||||
}
|
Loading…
Reference in New Issue