个人头像照片 wangccsy

个人介绍

前一个帐号wangccsy@126.com不知道怎么的就成了企业帐号,改不成个人。所以重新注册了一个个人帐号。老程序员。精通JAVA,C#,数据库,对软件开发过程和流程熟悉。考取系统分析师,项目管理师和系统架构设计师等软件资格考试认证。愿意和大家一起前进。

  • 最新动态
  • 文章
  • 问答

2019年08月

  • 08.31 21:46:54
    发表了文章 2019-08-31 21:46:54

    C# 成员默认访问权限(public、private、protected、internal)

    1.C#五个修饰符的权限修饰符    级别    适用成员        解释public    公开    类及类成员的修饰符   对访问成员没有级别限制private    私有    类成员的修饰符     只能在类的内部访问protected   受保护的  类成员的修饰符     ...

2019年07月

  • 07.10 10:10:56
    发表了文章 2019-07-10 10:10:56

    让你迷糊的Log4python

    在日志界,最著名的是Log4J(Java日志框架),很多开发语言都基于Log4j实现了自己的日志框架,如.net下的Log4net,PHP的Log4PHP(都是Apache软件基金会的Logging下的开源项目)。

2019年06月

  • 06.26 11:17:39
    发表了文章 2019-06-26 11:17:39

    浅析C#/Java程序中字符串操作的性能问题。

    在C#等面向对象语言中,虽然String是引用类型,但和普通的引用类型相关还是有较大的特殊型的。主要体现在两点:string中只有两个只读的属性,没有可设置的属性,所以说string 类型的实例具有固定不变性。
  • 06.21 09:41:39
    发表了文章 2019-06-21 09:41:39

    第二十七章:自定义渲染器(六)

    有趣的是,Android SeekBar小部件具有与Steps属性等效的功能,但不等同于Minimum和Maximum属性! 这怎么可能? SeekBar实际上定义了一个名为Max的整数属性,SeekBar的Progress属性始终是一个从0到Max的整数。
  • 06.19 09:13:43
    发表了文章 2019-06-19 09:13:43

    第二十七章:自定义渲染器(五)

    渲染器和事件(1)大多数Xamarin.Forms元素都是交互式的。他们通过触发事件来响应用户输入。如果在Xamarin.Forms自定义元素中实现事件,则可能还需要在呈现器中为本机控件触发的相应事件定义事件处理程序。
  • 06.11 09:37:02
    发表了文章 2019-06-11 09:37:02

    第二十七章:自定义渲染器(四)

    渲染器和属性(2)现在,对于iOS,EllipseUIView类是存在的,可以使用EllipseUIView作为本机控件来编写EllipseViewRenderer。 从结构上讲,这个类几乎与Windows渲染器相同:using System.
  • 06.06 16:01:18
    发表了文章 2019-06-06 16:01:18

    第二十七章:自定义渲染器(三)

    渲染器和属性(1)Xamarin.Forms包含一个BoxView元素,用于显示矩形颜色块。 你有没有希望你有类似的东西画一个圆圈,或使它更通用,椭圆?这就是EllipseView的目的。 但是,因为您可能希望在多个应用程序中使用EllipseView,所以它在第20章“异步和文件I / O”中介绍的Xamarin.FormsBook.Platform库中实现。
  • 06.05 09:29:33
    发表了文章 2019-06-05 09:29:33

    【阿里云入门之】如何快速创建弹性云服务器

    要使用阿里云的弹性云服务器ECS,必须确保已经拥有阿里云的帐号并且通过实名认证。如果还没有帐号可访问阿里云官网或者云栖社区进行注册。注册阿里云帐号注册方式很简单,以官网为例,打开浏览器,输入官网www.aliyun.com,点击如下图的免费注册按钮,弹出的界面输入用户名密码及手机等相关信息,如下图:注册成功后实名认证可使用身份证(需要几个工作日人工处理)或者银行卡(这个方式比较快)。
  • 06.04 13:52:40
    发表了文章 2019-06-04 13:52:40

    在阿里云ECS上部署Apache和Tomcat并整合

    首先需要购买阿里云ECS服务器。我购买的是低配置,OS为Ubuntu18.04。本文中所有的命令操作均是以Putty连接到ECS服务器后进行的操作。一、基本环境安装准备要运行Tomcat,首先要确认有没有安装Java。
  • 06.04 10:01:05
    发表了文章 2019-06-04 10:01:05

    初次使用阿里云ECS

    这两天,使用阿里云的代金卷购买了一个最最低配置的ECS(突发性能实例)。配置是很低很低的那种(估计没有比这再低配置的了)。主要是想学习和验证一下使用Eclipse部署到ECS。不过比较手欠的是,今天在了解Ubuntu18.04的iptables命令的时候,尝试了一下iptables-save导出规则。
  • 06.03 13:18:10
    发表了文章 2019-06-03 13:18:10

    第二十七章:自定义渲染器(二)

    您好,自定义渲染器!HelloRenderers程序主要演示编写简单渲染器所需的开销。 该程序定义了一个名为HelloView的新View衍生,旨在显示一个简单的固定文本字符串。 这是HelloRenderers可移植类库项目中的完整HelloView.cs文件:using Xamarin.Forms;namespace HelloRenderers{public class HelloView : View {}}而已! 但请注意,该类被定义为public。

2019年05月

  • 05.31 09:47:53
    发表了文章 2019-05-31 09:47:53

    第二十七章:自定义渲染器(一)

    Xamarin.Forms的核心可能看起来很神奇:像Button这样的单个元素在iOS,Android和Windows操作系统下显示为本机按钮的能力。在本章中,您将看到如何在所有三个平台上的Xamarin.Forms中的每个元素都由称为渲染器的特殊类支持。
正在加载, 请稍后...
滑动查看更多
正在加载, 请稍后...
暂无更多信息
  • 回答了问题 2019-07-22

    阿里邮箱登陆界面不能显示,试过好几个浏览器了

    我使用手机浏览器尝试了一下是可以的。你可以尝试一下。如果是走的代理网络,可能是代理服务器禁止了。
    踩0 评论0
  • 回答了问题 2019-07-22

    有时无法ssh

    1、服务端配置
    sudo vi /etc/ssh/sshd_config
    ClientAliveInterval 60     #服务端主动向客户端请求响应的间隔
    ClientAliveCountMax 10    #服务器发出请求后客户端没有响应的次数达到一定值就自动断开
    sudo restart ssh

    2、客户端配置
    sudo vi /etc/ssh/ssh_config  #或~/.ssh/config
    TCPKeepAlive=yes
    ServerAliveInterval 60   #客户端主动向服务端请求响应的间隔

    ssh -i <key-file> -o StrictHostKeyChecking=no -o TCPKeepAlive=yes -o ServerAliveInterval=30 ubuntu@<ip>

     上述方法,客户端配置和服务器端配置选择一个即可。如果你使用的是PUTTY,还可以在PUTTY的Connection项中,将Seconds between keepalives(0 to turn off)后面的0修改为60(代表60秒一请求)也可以。
    踩0 评论0
  • 回答了问题 2019-07-22

    远程无法连接mysql

    首先,确认你的MySQL已经映射到公网IP端口。其实,确认你的网络环境。再次,合理设置超时时间。
    踩0 评论0
  • 回答了问题 2019-07-22

    阿里云创建信息模板省份格式不对

    你填写的是什么内容 ?
    踩0 评论0
  • 回答了问题 2019-07-22

    RDS 查看慢日志明细发现导航栏不见了

    按返回键回退。
    踩0 评论0
  • 回答了问题 2019-07-22

    人脸查找的中的向人脸库增加照片API,请问人脸库在哪里看

    存在于阿里云数据中心服务器中。比如 face.cn-shanghai.aliyuncs.com是中国上海的数据中心人脸库中。
    踩0 评论0
  • 回答了问题 2019-03-06

    ecs 上vmware虚拟机启动失败

    你新建的虚拟机安装操作系统了吗?ECS支持在虚拟机里安装操作系统吗?
    踩0 评论0
  • 回答了问题 2019-01-25

    腾讯云备案了服务器还要继续备案吗


    还是要备案的。
    踩0 评论0
  • 回答了问题 2019-07-17

    [@倚贤][¥20]NIO原理

    1.阻塞与同步
    2.BIO与NIO对比
    3.NIO简介
    4.缓冲区Buffer
    5.通道Channel
    6.反应堆
    7.选择器
    8.NIO源码分析
    9.AIO
    1.阻塞与同步

    1)阻塞(Block)和非租塞(NonBlock):

    阻塞和非阻塞是进程在访问数据的时候,数据是否准备就绪的一种处理方式,当数据没有准备的时候阻塞:往往需要等待缞冲区中的数据准备好过后才处理其他的事情,否則一直等待在那里。

    非阻塞:当我们的进程访问我们的数据缓冲区的时候,如果数据没有准备好则直接返回,不会等待。如果数据已经准备好,也直接返回

    2)同步(Synchronization)和异步(Async)的方式:

    同步和异步都是基于应用程序私操作系统处理IO事件所采用的方式,比如同步:是应用程序要直接参与IO读写的操作。异步:所有的IO读写交给搡作系统去处理,应用程序只需要等待通知。

    同步方式在处理IO事件的时候,必须阻塞在某个方法上靣等待我们的IO事件完成(阻塞IO事件或者通过轮询IO事件的方式).对于异步来说,所有的IO读写都交给了搡作系统。这个时候,我们可以去做其他的事情,并不拓要去完成真正的IO搡作,当搡作完成IO后.会给我们的应用程序一个通知

    同步:阻塞到IO事件,阻塞到read成则write。这个时候我们就完全不能做自己的事情,让读写方法加入到线程里面,然后阻塞线程来实现,对线程的性能开销比较大,

    参考:https://blog.csdn.net/CharJay_Lin/article/details/81259880
    2.BIO与NIO对比

    block IO与Non-block IO
    1)区别
    IO模型 IO NIO
    方式 从硬盘到内存 从内存到硬盘
    通信 面向流(乡村公路) 面向缓存(高速公路,多路复用技术)
    处理 阻塞IO(多线程) 非阻塞IO(反应堆Reactor)
    触发 无 选择器(轮询机制)

    2)面向流与面向缓冲
    Java NIO和IO之间第一个最大的区别是,IO是面向流的.NIO是面向缓冲区的。Java IO面向流意味着毎次从流中读一个成多个字节,直至读取所有字节,它们没有被缓存在任何地方,此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的教据,需要先将它缓存到一个缓冲区。Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,霱要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数裾。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。

    3)阻塞与非阻塞
    Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。 Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。

    4)选择器(Selector)
    Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择"通道:这些通里已经有可以处理的褕入,或者选择已准备写入的通道。这选怿机制,使得一个单独的线程很容易来管理多个通道。

    5)NIO和BIO读取文件
    BIO读取文件:链接
    BIO从一个阻塞的流中一行一行的读取数据

    image | left | 469x426

    NIO读取文件:链接
    通道是数据的载体,buffer是存储数据的地方,线程每次从buffer检查数据通知给通道

    image | left | 559x394

    6)处理数据的线程数
    NIO:一个线程管理多个连接
    BIO:一个线程管理一个连接
    3.NIO简介

    在Java1.4之前的I/O系统中,提供的都是面向流的I/O系统,系统一次一个字节地处理数据,一个输入流产生一个字节的数据,一个输出流消费一个字节的数据,面向流的I/O速度非常慢,而在Java 1.4中推出了NIO,这是一个面向块的I/O系统,系统以块的方式处理处理,每一个操作在一步中产生或者消费一个数据库,按块处理要比按字节处理数据快的多。

    在NIO中有几个核心对象需要掌握:缓冲区(Buffer)、通道(Channel)、选择器(Selector)。
    参考:链接

    image2.png | center | 851x383
    4.缓冲区Buffer

    缓冲区实际上是一个容器对象,更直接的说,其实就是一个数组,在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,它也是写入到缓冲区中的;任何时候访问 NIO 中的数据,都是将它放到缓冲区中。而在面向流I/O系统中,所有数据都是直接写入或者直接将数据读取到Stream对象中。

    在NIO中,所有的缓冲区类型都继承于抽象类Buffer,最常用的就是ByteBuffer,对于Java中的基本类型,基本都有一个具体Buffer类型与之相对应,它们之间的继承关系如下图所示:
    image3.png | center | 650x368
    1)其中的四个属性的含义分别如下:
    容量(Capacity):缓冲区能够容纳的数据元素的最大数量。这一个容量在缓冲区创建时被设定,并且永远不能改变。
    上界(Limit):缓冲区的第一个不能被读或写的元素。或者说,缓冲区中现存元素的计数。
    位置(Position):下一个要被读或写的元素的索引。位置会自动由相应的 get( )和 put( )函数更新。
    标记(Mark):下一个要被读或写的元素的索引。位置会自动由相应的 get( )和 put( )函数更新。

    2)Buffer的常见方法如下所示:
    flip(): 写模式转换成读模式
    rewind():将 position 重置为 0 ,一般用于重复读。
    clear() :
    compact(): 将未读取的数据拷贝到 buffer 的头部位。
    mark(): reset():mark 可以标记一个位置, reset 可以重置到该位置。
    Buffer 常见类型: ByteBuffer 、 MappedByteBuffer 、 CharBuffer 、 DoubleBuffer 、 FloatBuffer 、 IntBuffer 、 LongBuffer 、 ShortBuffer 。

    3)基本操作
    Buffer基础操作: 链接
    缓冲区分片,缓冲区分配,直接缓存区,缓存区映射,缓存区只读:链接

    4)缓冲区存取数据流程
    存数据时position会++,当停止数据读取的时候
    调用flip(),此时limit=position,position=0
    读取数据时position++,一直读取到limit
    clear() 清空 buffer ,准备再次被写入 (position 变成 0 , limit 变成 capacity) 。
    5.通道Channel

    通道是一个对象,通过它可以读取和写入数据,当然了所有数据都通过Buffer对象来处理。我们永远不会将字节直接写入通道中,相反是将数据写入包含一个或者多个字节的缓冲区。同样不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。
    image4.png | center | 368x191
    在NIO中,提供了多种通道对象,而所有的通道对象都实现了Channel接口。它们之间的继承关系如下图所示:
    image5.png | center | 650x517

    1)使用NIO读取数据
    在前面我们说过,任何时候读取数据,都不是直接从通道读取,而是从通道读取到缓冲区。所以使用NIO读取数据可以分为下面三个步骤:

    从FileInputStream获取Channel
    创建Buffer
    将数据从Channel读取到Buffer中
    例子:链接
    

    2)使用NIO写入数据
    使用NIO写入数据与读取数据的过程类似,同样数据不是直接写入通道,而是写入缓冲区,可以分为下面三个步骤:

    从FileInputStream获取Channel
    创建Buffer
    将数据从Channel写入到Buffer中
    例子:链接
    

    6.反应堆

    1)阻塞IO模型
    在老的IO包中,serverSocket和socket都是阻塞式的,因此一旦有大规模的并发行为,而每一个访问都会开启一个新线程。这时会有大规模的线程上下文切换操作(因为都在等待,所以资源全都被已有的线程吃掉了),这时无论是等待的线程还是正在处理的线程,响应率都会下降,并且会影响新的线程。
    image6.png | center | 739x336

    2)NIO
    Java NIO是在jdk1.4开始使用的,它既可以说成“新IO”,也可以说成非阻塞式I/O。下面是java NIO的工作原理:
    1.由一个专门的线程来处理所有的IO事件,并负责分发。
    2.事件驱动机制:事件到的时候触发,而不是同步的去监视事件。
    3.线程通讯:线程之间通过wait,notify等方式通讯。保证每次上下文切换都是有意义的。减少无谓的线程切换。

    image7.png | center | 689x251

    注:每个线程的处理流程大概都是读取数据,解码,计算处理,编码,发送响应。
    7.选择器

    传统的 server / client 模式会基于 TPR ( Thread per Request ) .服务器会为每个客户端请求建立一个线程.由该线程单独负贵处理一个客户请求。这种模式带未的一个问题就是线程数是的剧增.大量的线程会增大服务器的开销,大多数的实现为了避免这个问题,都采用了线程池模型,并设置线程池线程的最大数量,这又带来了新的问题,如果线程池中有 200 个线程,而有 200 个用户都在进行大文件下载,会导致第 201 个用户的请求无法及时处理,即便第 201 个用户只想请求一个几 KB 大小的页面。传统的 Sorvor / Client 模式如下围所示:
    image8.png | center | 597x286
    NIO 中非阻塞IO采用了基于Reactor模式的工作方式,IO调用不会被阻塞,相反是注册感兴趣的特点IO事件,如可读数据到达,新的套接字等等,在发生持定率件时,系统再通知我们。 NlO中实现非阻塞IO的核心设计Selector,Selector就是注册各种IO事件的地方,而且当那些事件发生时,就是这个对象告诉我们所发生的事件。
    image9.png | center | 462x408
    当有读或者写等任何注册的事件发生时,可以从Selector中获得相应的SelectionKey,同时从SelectionKey中可以找到发生的事件和该事件所发生的具体的SelectableChannel,以获得客户端发送过来的数据。
    使用NIO中非阻塞IO编写服务器处理程序,有三个步骤
    1.向Selector对象注册感兴趣的事件
    2.从Selector中获取感兴趣的事件
    3.根据不同事件进行相应的处理
    8.NIO源码分析

    Selector是NIO的核心
    epool模型

    1)Selector
    Selector的open()方法:链接

    2)ServerSocketChannel
    ServerSocketChannel.open() 链接
    9.AIO

    Asynchronous IO
    异步非阻塞IO

    BIO ServerSocket
    NIO ServerSocketChannel
    AIO AsynchronousServerSocketChannel

    踩0 评论0
  • 回答了问题 2019-07-17

    [@wangccsy][¥20]Java工程师如何规划自己的职业生涯?

    Java初级-中级-高级-架构-技术管理

    踩0 评论0
  • 回答了问题 2019-07-17

    [@wangccsy][¥20]单体应用向分布式高并发系统重构需要注意的问题及性能考虑?

    1.增大系统容量。我们的业务量越来越大,而要能应对越来越大的业务量,一台机器的性能已经无法满足了,我们需要多台机器才能应对大规模的应用场景。所以,我们需要垂直或是水平拆分业务系统,让其变成一个分布式的架构。

    2.加强系统可用。我们的业务越来越关键,需要提高整个系统架构的可用性,这就意味着架构中不能存在单点故障。这样,整个系统不会因为一台机器出故障而导致整体不可用。所以,需要通过分布式架构来冗余系统以消除单点故障,从而提高系统的可用性。

    3.因为模块化,所以系统模块重用度更高

    4.因为软件服务模块被拆分,开发和发布速度可以并行而变得更快

    5.系统扩展性更高

    6.团队协作流程也会得到改善

    踩0 评论0
  • 回答了问题 2019-07-17

    [@wangccsy][¥20]java函数式编程是未来发张趋势吗?

    个人感觉是这样,不管是.net,还是Java,都在朝这个方向发展。

    踩0 评论0
  • 回答了问题 2019-07-17

    [@wangccsy][¥20]刚入行的java程序员该如何规划自己的成长路线?

    第一,制定自己的职场规划(方向)。作为职场人来说,制定自己的职场规划是比较重要的。具体到Java程序员来说,要给自己定一个方向,并制定对应的阶段性目标和长期目标。如果想在程序员这条路上走的更远,就一定要有一个自己的主攻方向,比如大数据就是个不错的选择。第二,合理利用时间提高自己的能力。程序员能力的提升分为两个部分,一部分是工作本身带来的提高,另一部分是主动学习带来的提高。通过工作带来的提高往往是有一定期限的,如果在一个岗位上工作超过3年,那么每天通过工作获得的提升是十分有限的,此时要想获得持续不断的提高就要借助自主学习,或者是转岗。自主学习的重点在于时间的利用,大部分程序员的业余时间都是碎片化的,如何有效利用碎片化时间来系统学习是非常考验程序员的。

    刚入行的Java程序员,应该如何学习提高自己?
    第三,注重交流。对于程序员来说,交流是提升自己的重要渠道,尤其是对于刚入行的程序员来说,更要多与其他人交流,以便于获得更多的信息量。这些交流包括技术交流、业务交流等内容,通过交流来吸收更多的知识,然后指导自己的工作。按照历史经验来看,往往善于交流的程序员成长的更快第五,制定一个清晰的发展计划和阶段性目标。

    刚入行的Java程序员,应该如何学习提高自己?
    第四,制定一个清晰的发展计划和阶段性目标。随着信息化社会的不断发展,程序员在未来的发展空间非常大,尤其是研发级程序员。作为程序员来说要紧跟技术发展的脚步,不断更新自己的知识结构,只有这样才能在职场获得持续的提高。

    踩0 评论0
  • 回答了问题 2019-07-17

    [@wangccsy][¥20]web系统后台如何转型成架构师或大数据算法工程师?

    转型大数据,要点归纳

    1、重视基础

    2、发挥专长

    3、准备充分

    4、首选公司内部转岗

    踩0 评论0
  • 回答了问题 2019-07-17

    [@wangccsy][¥20]如何设计高并发下的限流架构保证应用的可用性?

    系统在设计之初就会有一个预估容量,长时间超过系统能承受的TPS/QPS阈值,系统可能会被压垮,最终导致整个服务不够用。为了避免这种情况,我们就需要对接口请求进行限流。

    限流的目的是通过对并发访问请求进行限速或者一个时间窗口内的的请求数量进行限速来保护系统,一旦达到限制速率则可以拒绝服务、排队或等待。

    常见的限流模式有控制并发和控制速率,一个是限制并发的数量,一个是限制并发访问的速率,另外还可以限制单位时间窗口内的请求数量。
    控制并发数量

    属于一种较常见的限流手段,在实际应用中可以通过信号量机制(如Java中的Semaphore)来实现。
    举个例子,我们对外提供一个服务接口,允许最大并发数为10,代码实现如下:

    public class DubboService {    private final Semaphore permit = new Semaphore(10, true);    public void process(){        try{
                permit.acquire();            //业务逻辑处理
     
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                permit.release();
            }
        }
    }
    

    在代码中,虽然有30个线程在执行,但是只允许10个并发的执行。Semaphore的构造方法Semaphore(int permits) 接受一个整型的数字,表示可用的许可证数量。Semaphore(10)表示允许10个线程获取许可证,也就是最大并发数是10。Semaphore的用法也很简单,首先线程使用Semaphore的acquire()获取一个许可证,使用完之后调用release()归还许可证,还可以用tryAcquire()方法尝试获取许可证。
    控制访问速率

    在我们的工程实践中,常见的是使用令牌桶算法来实现这种模式,其他如漏桶算法也可以实现控制速率,但在我们的工程实践中使用不多,这里不做介绍,读者请自行了解。

    在Wikipedia上,令牌桶算法是这么描述的:

    每过1/r秒桶中增加一个令牌。
    
    桶中最多存放b个令牌,如果桶满了,新放入的令牌会被丢弃。
    
    当一个n字节的数据包到达时,消耗n个令牌,然后发送该数据包。
    
    如果桶中可用令牌小于n,则该数据包将被缓存或丢弃。
    

    令牌桶控制的是一个时间窗口内通过的数据量,在API层面我们常说的QPS、TPS,正好是一个时间窗口内的请求量或者事务量,只不过时间窗口限定在1s罢了。以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。令牌桶的另外一个好处是可以方便的改变速度,一旦需要提高速率,则按需提高放入桶中的令牌的速率。

    在我们的工程实践中,通常使用Guava中的Ratelimiter来实现控制速率,如我们不希望每秒的任务提交超过2个:

    //速率是每秒两个许可final RateLimiter rateLimiter = RateLimiter.create(2.0);
     
    void submitTasks(List tasks, Executor executor) {    for (Runnable task : tasks) {
            rateLimiter.acquire(); // 也许需要等待
            executor.execute(task);
        }
    }
    

    控制单位时间窗口内请求数

    某些场景下,我们想限制某个接口或服务 每秒/每分钟/每天 的请求次数或调用次数。例如限制服务每秒的调用次数为50,实现如下:

    import com.google.common.cache.CacheBuilder;import com.google.common.cache.CacheLoader;import com.google.common.cache.LoadingCache;import java.util.concurrent.ExecutionException;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicLong;
     
        private LoadingCache<Long, AtomicLong> counter =
                CacheBuilder.newBuilder()                    .expireAfterWrite(2, TimeUnit.SECONDS)                    .build(new CacheLoader<Long, AtomicLong>() {
                            @Override
                            public AtomicLong load(Long seconds) throws Exception {
                                return new AtomicLong(0);
                            }
                        });
     
        public static long permit = 50;
     
        public ResponseEntity getData() throws ExecutionException {
     
            //得到当前秒
            long currentSeconds = System.currentTimeMillis() / 1000;
            if(counter.get(currentSeconds).incrementAndGet() > permit) {
                return ResponseEntity.builder().code(404).msg("访问速率过快").build();
            }
            //业务处理
     
        }
    
    踩0 评论0
  • 回答了问题 2019-07-17

    [@wangccsy][¥20]Oracle jdk收费之后,对于java的生态会有哪些影响?阿里自己会开源出相关这部分的生态吗?

    DK8从2019年1月开始就要收费了,怎么办呢?

    其实这个问题本身就是有问题的,因为收费的并不是JDK8 , 而是JDK8后续的update (更新) 。

    什么是update? 如果你下载过JDK, 就会看到那些8u191, 8u192这样的东西,191,192就是update 的编号。

    这些update中通常会包含对JDK bug的fix ,或者一些功能的改变,增强, 拿update 172为例:

    1. 这个update 修改了下面两个方法的文档,让文档描述和方法的实现一致:

    java.awt.Toolkit.getImage(URL u)

    java.awt.Toolkit.createimage(URL u)

    1. 增加了在Windows8 及以上版中,对Swing/AWT 文本组件自动显示触摸键盘的功能
    2. 36个Bug Fix

    假设JDK 8u192是2018年的最后一个update , 你下载并且安装了,那可以继续免费使用下去,没有任何问题。

    但是从2019年1月开始,如果你还想获取JDK的update , 对不起,你需要付费订阅。

    这个订阅服务的价格是这样的:

    对于PC, 每用户每月是2.5美元,对于服务器/云部署,每个processor 每月是25美元, 当然,数量多的话可以打折。

    Oracle 为什么要这么干呢?

    我推测有两个原因, 第一个原因可以理解: Oracle JDK8 2014年3月发布, 到2019年1月正式进入“End of Public Updates”, 这个版本Oracle支持了将近5年时间,一个版本的软件不可能无限期地支持下去,那样维护成本太高。

    第二个原因可能是没有多少人购买它的Java SE Advanced, Java SE Advanced Desktop 或者Java SE Suite, 这三个家伙是什么东西? 我们稍后解释。

    你也许注意到了, 我刚才再说JDK的时候,特别加上了Oracle 这个词,这是因为Java虚拟机的规范是开放的,任何人都可以去实现。

    老刘在2017年编程提高群第一季中,不就和大家一起实现了一个极为简单的版本吗? 当然那不能称为JVM ,只实现了对Class文件的解析,和一个能实现顺序,分支,循环,多态的简单执行引擎。

    其实现在的JDK提供者非常多,不像微软的.NET,独此一家,别无分号。
    Open JDK

    这个不多说,免费的开源实现,以GPL License发布,很多Linux发行版中都会包含这个Open JDK 。

    参与开发的大佬们有Oracle, RedHat (已被IBM收购), Azul System, IBM , Apple , SAP。
    Oracle JDK

    就是我们常说的Java JDK , 也是最常用的一个,是Oracle公司(收购了开发Java的Sun公司)对Java SE的实现。

    如果更详细分的话,可以分为Oracle JDK和 Oracle JRE。

    比如你想玩Minecraft 这样需要Java的游戏, 那只需要从java.com下载一个JRE就够了。

    如果你想基于Java做开发,那就需要从Oracle Technology Network(OTN)网站上下载JDK了。
    其他公司提供的JDK

    有实力的大公司,都有可能开发自己的JDK , 比如IBM ,肯定要为自家的操作系统AIX,还有z/OS开发SDK。

    我在IBM工作的时候,根本就没有用过Oracle JDK,公司也不让用啊。

    HP,SAP也有自己的JDK , 可以为自己的硬件和软件做定制。

    Oracle Java SE Advanced, Java SE Advanced Desktop, Java SE Suite

    这名字老长了,也有点费解,简单来说,这是个收费的服务, 是Oracle 为企业级用户提供的高级工具和功能,可以监控、部署、管理企业级的Java程序,与此同时,你还可以下载那些老版本的JDK及其update。

    换句话说,如果你购买了这个服务,自然就不用担心什么JDK update 收费的问题。

    但是问题在于,到底有多少公司再使用这个服务? 如果你的公司在使用,欢迎告知。

    所以我猜测Oracle耍了一点小手段, 以后不要这个收费的服务了,把这些高级的功能加上JDK update 打包,统一成一个新的服务,就是之前说的订阅服务。
    总结一下

    如果你的公司已经买了这个Java SE Advanced (或者 Advanced Desktop), Java SE Suite的License, 什么都不用担心,你很安全。

    如果你的公司正在使用Oracle JDK 8 并且还想在2019年1月之后获得那些更新和支持,你需要购买Orace 的订阅服务。

    如果你的公司一直在在升级你的Oracle JDK ,比如说已经升级到JDK9了,你什么服务都不用购买, 因为那个订阅服务主要解决的是老版本的Update 的问题。

    或者可以选择一个没有public update的Oracle JDK , 这也很常见,很多JDK已经非常稳定了, 比如Oracle JDK 7 发布日期是2011年7月, “End of Public Updates” 是2015年4月, 我估计现在还有不少公司还在使用JDK7这个已经没有public update的版本吧!

    如果真的出现了巨大的安全漏洞,你又没法升级JDK ,那只好去购买订阅服务去Fix了。

    当然,你的公司也可以选择纯开源OpenJDK。

    注意,我这里说的都是公司,都是商业用途,如果只是个人学习Java的话,没什么影响!

    踩0 评论0
  • 回答了问题 2019-07-17

    [@wangccsy][¥20]jdk8对hashmap做了哪些优化?

    在Java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结构,但是在jdk1.8里
    加入了红黑树的实现,当链表的长度大于8时,转换为红黑树的结构。

    这里写图片描述

    从上图中可以看出,Java中HashMap采用了链地址法。链地址法,简单来说,就是数组加链表的结合。在每个数组元素上都一个链表结构,当数据被Hash后,得到数组下标,把数据放在对应下标元素的链表上。

     */
    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;//用于定位数组索引的位置
        final K key;
        V value;
        Node<K,V> next;//链表的下一个Node
    
        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
    

    Node是HashMap的一个内部类,实现了Map.Entry接口,本质是就是一个映射(键值对)。

    有时两个key会定位到相同的位置,表示发生了Hash碰撞。当然Hash算法计算结果越分散均匀,Hash碰撞的概率就越小,map的存取效率就会越高。

    HashMap类中有一个非常重要的字段,就是 Node[] table,即哈希桶数组,明显它是一个Node的数组。如果哈希桶数组很大,即使较差的Hash算法也会比较分散,如果哈希桶数组数组很小,即使好的Hash算法也会出现较多碰撞,所以就需要在空间成本和时间成本之间权衡,其实就是在根据实际情况确定哈希桶数组的大小,并在此基础上设计好的hash算法减少Hash碰撞。那么通过什么方式来控制map使得Hash碰撞的概率又小,哈希桶数组(Node[] table)占用空间又少呢?答案就是好的Hash算法和扩容机制。

    如果哈希桶数组很大,即使较差的Hash算法也会比较分散,如果哈希桶数组数组很小,即使好的Hash算法也会出现较多碰撞,所以就需要在空间成本和时间成本之间权衡,其实就是在根据实际情况确定哈希桶数组的大小,并在此基础上设计好的hash算法减少Hash碰撞。

    这里存在一个问题,即使负载因子和Hash算法设计的再合理,也免不了会出现拉链过长的情况,一旦出现拉链过长,则会严重影响HashMap的性能。于是,在JDK1.8版本中,对数据结构做了进一步的优化,引入了红黑树。而当链表长度太长(默认超过8)时,链表就转换为红黑树,利用红黑树快速增删改查的特点提高HashMap的性能,其中会用到红黑树的插入、删除、查找等算法

    踩0 评论0
  • 回答了问题 2019-07-17

    [@wangccsy][¥20]如何学习JVM虚拟机?(学生)

    jvm学习,推荐书籍:《深入理解java虚拟机》-周志明著

    下载地址(mobi格式):https://pan.baidu.com/s/1HF9vKVJzw2p4WejMdWbhhA

    密码:uesy

    踩0 评论0
  • 回答了问题 2019-07-17

    [@wangccsy][¥20]异步处理的原理是什么?

    主要是通过回调方式来实现。其实就是观察者模式差不多。

    踩0 评论0
  • 回答了问题 2019-07-17

    [@wangccsy][¥20]很多时候通过给一个非String类型变量加空字符串(+“”)将其转换为String类型,这样做有什么缺点吗?

    如果我们没有实现相应的toString方法,得到的结果就可想而知了。

    踩0 评论0
正在加载, 请稍后...
滑动查看更多