自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

朱登凯的专栏

业余时间喜欢写点技术博客,读点无用之书

  • 博客(227)
  • 资源 (6)
  • 收藏
  • 关注

原创 基于zookeeper实现领导选举和分布式锁

上一篇博客讨论了基于zookeeper的分布式队列的机制,这个机制除了可以做分布式队列以外,稍加修改,还可以做更多的事情,例如接下来要讨论的领导选举和分布式锁的功能等。领导选举领导选举的应用场景可以理解为:多个节点同时想干一件事(都想当老大),但最终只有一个节点被授权(老大只可能有一个)例如:一主多从模式下,如果主节点挂掉了,那么所有的从节点都要竞选成为主节点,但只有一个节点可以成为主...

2018-07-15 18:18:39 1016

原创 git变基

假设有这么一个场景,一个分支一共有50次提交,其中第31-40次的提交是一个新功能的代码,这10次提交如果放到一个新的分支上来开发会更好,但当时没想到。后来产品该需求了(for example…),这10次提交的代码要被废掉,这时候应该怎么处理呢?可以一个个地revert,但这种方法很不优雅。由这个问题引出本篇博客要讨论的主题:变基。git提供了两个命令可以很方便地来解决上面的问题,分别是git ...

2018-04-16 22:25:25 4836

原创 git暂存区[重要]

本篇来讨论git的核心,暂存区。首先上一张图。左侧是工作区,也就是我们本地电脑上的文件,中间的Index就是我们讨论的暂存区,右侧是HEAD。HEAD是一个头指针,我会在下一篇博客中讨论HEAD,此处你先理解为HEAD就是git版本库。上面的这张图,非常非常地重要,如果我下面讨论的东西你有不明白的,这张图可能都会给你答案。其实,git的绝大部分的操作都是在将文件在工作区、暂存区和版本库中移来移去,就

2017-06-11 23:24:45 2210 8

原创 Spring定义和装配Bean

我在上一篇博客中讨论了Spring中的IOC和AOP,本篇文章通过代码来演示一下Spring到底是如何实现IOC的。本篇博客我会介绍在Spring中如何定义和装载Java Bean。业务场景还是人开车的例子。首先,定义一个Car接口和两个实现了Benz和BMW,然后定义一个Person类,Person类依赖Car接口。public interface Car { voi...

2015-10-18 17:22:56 5726 3

原创 设计模式之命令模式

命令模式的关键之处把每一个具体的请求都封装成了一个对象,即命令对象,这些请求实现了同一个接口,而且还不亲自执行具体任务。每一个命令对象都和命令的具体执行者组合在一起,由命令的具体执行者来执行命令。

2015-05-29 06:13:33 2423 3

原创 如何批量取消多个goroutine

goroutine 无法自动终结,如果一个任务可以分片进行(而不是一个IO走到黑),那么可以借助select来监听一个取消通道。如果对于单个goroutine或固定数量的多个goroutine,我们只需向取消通道中发送等量的事件即可。但对于不确定数量的goroutine,如何保证都通知到他们呢?可以借助通道的关闭特性,当通道关闭后,从通道接收消息额操作会立刻返回。也就是说,如果想向不确定数量的一批goroutine发送一个事件,且这种事件是一次性的,不会重复发送,可以让所有goroutine监听一个通道

2021-11-14 21:36:36 390

原创 golang中的计时器与select

golang中的select机制让我对大师的设计水平赞叹不已,它基于多个阻塞的通道操作(发送或接收),哪个可以执行,就执行哪个。select {case <- ch1: // ...case x <- ch2: // use x ...case ch3 <- y: // ...}前两个case是接收,第三个case是发送。golang的运行机制是,当前的goroutine会阻塞,当ch1或ch2可以接收事件时,或者ch3可以发送事件时,就触发对应的case代码块,然后s

2021-11-14 21:35:40 766

原创 一个使用golang并行计算的例子

sync.WaitGroup的工作方式类似java里面的CountDownLatch,用于计数并阻塞等待。下面的例子,我们来编写一个并行任务,以并发的方式处理一个批次的任务,可以控制它的最大并发度,并在所有任务全部完成后返回一个结果。import ( "fmt" "sync" "time" "unicode/utf8")func concurrentPrinting(tasks []string, maxConcurrent int) int { tokens := make(chan

2021-11-14 21:34:22 425 1

原创 用缓冲通道实现阻塞队列

当通道(channel)没有指定最大长度(cap)时,它的最大长度是0,也就意味着发送操作将会阻塞,直到另一个goroutine在对应的通道上执行了接收操作,倒过来说也是成立的,接收操作将会阻塞,直到另一个goroutine在对应的通道上执行发送操作。也就是说,基于无缓冲队列的发送和接收是同步进行的,而基于缓冲通道的原理是,如果通道没有满,发送操作会立刻完成,如果通道内还有消息,接收操作也会立刻完成,否则,它们才会阻塞。创建缓冲通道的方法make(chan int, 3)上面的代码创建了一个cha

2021-11-14 21:32:50 101

原创 goroutine与channel

启动goroutine在golang中,一个活动单元被称为goroutine,通过go关键字来启动一个goroutine并立刻返回。f() // 调用f(),并等待结果go f() // 新建一个调用f()的goroutine,不用等待main函数运行在主goroutine中,当main函数返回时,所有的goroutine都将终结,进程将退出,释放所有资源。goroutine的粒度是一个函数,这个函数无需实现任何接口,也无需绑定到任何类中。我们也可以通过go关键字直接运行一个匿名函数,就像下面

2021-11-14 21:29:47 200

原创 使用golang实现一个简单地httpServer

golang的标准库中,可以使用http.ListenAndServe来启动一个httpServerfunc ListenAndServe(addr string, handler Handler) error { server := &Server{Addr: addr, Handler: handler} return server.ListenAndServe()}它接收两个参数,第一个是寄宿的地址,第二个是http.Handler接口。我们就来定义一个类来实现这个接口。typ

2021-11-14 21:28:10 514

原创 golang中的排序

golang中排序的底层逻辑golang中排序最底层的逻辑是是这段代码sort.Sort// Sort sorts data.// It makes one call to data.Len to determine n and O(n*log(n)) calls to// data.Less and data.Swap. The sort is not guaranteed to be stable.func Sort(data Interface) { n := data.Len() qu

2021-11-10 10:40:13 461

原创 golang中通过flag获取命令行参数

golang中的flag提供了一种基于命令行的、开箱即用的、提取命令行参数的方式。package mainimport ( "flag" "fmt")func main() { wordPtr := flag.String("word", "foo", "a string") numPtr := flag.Int("num", 123, "a number") flag.Parse() fmt.Printf("word = %s\n", *wordPtr) fmt.Printf

2021-11-10 10:39:24 661

原创 golang中的接口

接口类型的定义与实现接口是一种抽象类型,它仅包含一些方法签名,没有给出具体实现。接口意味着约定。你拿到一个接口以后,你可以通过查看它包含的方法来知道它能做什么。type Speaker interface { Speak() string}上面的代码定义了一个名为Speaker的接口,它包含一个方法。我们能从中看出来,Speak方法不需要提供参数就可以获取一个字符串,好像是要说点什么。type Employee struct { ID int Name, Addre

2021-11-10 10:38:07 175

原创 golang中的面向对象

声明方法声明方法的语法和声明普通函数非常类似,只是在函数名字前面加上一个参数,这个参数把这个方法绑定到它对应的类型上。func (e Employee) ToString() (description string) { return fmt.Sprintf("[%d, %s], from %s", e.ID, e.Name, e.Address)}注意这里的(e Employee),这里的Employee说明了这个ToString()方法属于Employee类型的方法,而e就类似其它语言中的t

2021-11-10 10:29:35 756

原创 golang中的defer

在golang中弱化了异常机制,defer是一种finally的实现机制,它的工作原理是这样的它加在一个函数调用前面,当执行到这一行时,它会计算参数表达式的值,但并不立刻执行函数调用;当函数结束运行时,开始执行defer的函数调用;如果在一个函数中出现了多个defer语句,那么当函数运行结束时,按照出栈顺序来执行它们;这样做的好处是,我们仿佛可以将finally语句块中的代码段,以更小的粒度、一行一行地穿插到主逻辑的不同位置,并且事后按照当时的参数去调用。func accumulate(cou

2021-11-10 10:27:49 774

原创 golang中的函数

函数的语法func name(param-list) (result-list){ body}实例// 比较直接的语法func add1(x int, y int) int { return x + y}// 同类型的参数(或返回值)可以放在一起,最后面声明一次类型就好func add2(x, y int) int { return x + y}// 将返回值也赋予一个变量名,可读性更好func add3(x, y int) (z int) { z

2021-11-10 10:26:59 88

原创 golang中使用JSON

golang标准库有一个名叫encoding/json的包,包含了JSON的序列化(Marshal)和反序列化(Unmarshal)的能力。通过成员标签控制JSON输出type Movie struct { Title string Year int `json:"released"` Color bool `json:"color,omitempty"` Actors []string}成员标签是一组有空格分开的键值对,格式为key:"value"。键j

2021-11-10 10:26:04 4728

原创 golang中的struct

struct是实现面向对象的重要技术,基本上都跟类型声明type name underlying-type结合使用。struct是值类型,所以它的零值是所有成员的零值。由于值类型在作为函数参数时的局限性,所以经常配合指针一起使用。声明type Employee struct { ID int Name string Address string}一行一个成员,中间没有逗号或分号,大写的成员可以在包外访问。如果类型相同,也可以考虑定义在一行,例如type

2021-11-10 10:25:03 291

原创 golang中的map

在golang中,map是散列表的引用,也就是说它是引用类型,像指针那样。map的类型是map[K]V,所有元素的key都K类型,所有元素的value都是V类型。初始化mapm := make(map[string]int) // 方式一m := map[string]int{} // 方式二避免对零值(未初始化)的map设置kv。var ages map[string]intages["tom"] = 12 // 异常var ages := map[string]int{}

2021-11-10 10:23:13 404

原创 golang中的slice

golang中的slice表示一个可变长度的数组,声明为 []T ,其中T是类型。 关于数组请参见:golang中的数组slice跟数组紧密相连,slice有三个属性,分别是:指针、长度(len)和容量(cap),其中指针指向底层数组,所以它天然依赖底层数组。从某种意义上来讲,slice更像一个结构体,这个结构体里面必然包含一个指针。slice的指针指向底层数组arr := [...]int{1, 2, 3, 4, 5}slice1 := arr[:3]for i := range slice1

2021-11-09 21:51:01 691

原创 golang中的数组

golang中的数组实现的比较保守,长度固定,属于值类型。数组的长度是数组类型的一部分,比如 [3]int和[4]int都是长度固定的数组,但它们两个的类型是不同的,因为长度不同。[]int是slice,没有指定长度。数组的初始化数组的类型一定是包含长度的,比如下面这两个var arr [3]int = [3]int{1, 2, 3}arr2 := [3]int{1, 2, 3}也可以让编译器来推断长度arr3 := [...]int{1, 2, 3}如果显式指定的话,初始化值的时候还

2021-11-09 21:49:40 118

原创 golang的常量

常量是一种表达式,编译器会对它做一些增强支持,比如如果修改常量的话则会编译失败。定义常量const pi = 3.14如果定义多个常量const ( pi = 3.14 e = 2.718)通过常量生成器iota来定义枚举类型type Weekday intconst ( Sunday Weekday = iota Monday Tuesday Wednesday Thursday Friday Saturday

2021-11-09 21:48:39 3246

原创 golang的string

golang中的string是不可变的字节序列,零值是空字符串,默认是UTF-8编码。golang中使用字符串最需要注意的是,golang中的字符串是字节序列,string == []byte,由于一个字符占用的字节数不确定,所以无法通过下标[i]的方式稳定地获取对应位置的字符。 也就意味着字符串的第i个字节,不一定就是第i个字符,原因请参考 unicode与UTF-8文字符号在golang中被称为rune,发音为/ru:n/,意思是符号。由于utf-8最多使用4个字节来编码,所以rune类型是int3

2021-11-09 20:34:45 525

原创 unicode与UTF-8

字符集要解决的第一个问题是描述文字,包括字符、数字和符号等。最开始的方案是ASCII,它的编码规则也很简单,一个code point占用一个字节。它由美国人发明,在英文环境下运行的很好。当计算机越来越普及时,人们发现ASCII字符集无法显示其它国家的语言文字,比如中文,于是各个国家就开始发明自己的编码,中国人发明了GB2312和GBK等,来解决中文的显示问题。为了避免各国自己造轮子,ISO看不下去了,搞了一个UNICODE字符集,直接解决了世界上所有的语言字符集问题。但是,另外一个问题随之而来,就是存储

2021-11-09 20:33:40 148

原创 golang的作用域

作用域与生命周期不是一个概念,作用域是变量或其它声明出现的区域,是一个在编译阶段关注的问题,而生命周期是一个变量能被其它部分所引用的起止时间,是一个运行时的问题。如果块级作用域内部的一个变量的指针被赋值给包级别的变量(俗称逃逸),那么这个变量的作用域还是在这个块内,但这个变量的值却会始终存在,你无法通过变量本身访问它,但可以通过外部的指针来访问它。golang是典型的块级作用域,块(block) 有不同的层级,最外层是全局块,里面有 int, len() 等,再然后有 包 / 文件 / 函数 / if /

2021-11-09 20:31:19 262

原创 golang的包和文件

golang中的包的作用与其他语言中的模块或库是类似的,主要用于支持模块化、封装、单独编译、重用等。一个包提供了一个独立的命名空间,大写开头的内容对外export。一个包下可以包含多个以.go结尾的源文件。包的导入import "example.com/common/util"在上面的导入语句中,example.com/common/util被称为导入路径(import path),它的源代码存在于$GOPATH/example.com/common/util目录下。这个包被导入以后,会绑定一个

2021-11-09 20:30:17 156

原创 golang的类型声明(type)

通过type关键字来定义一个新的命名类型,它基于一个已有的底层类型。新的类型的结构和行为由底层类型决定,但明确表明了它与底层类型不一样,所以不能混用。语法:type name underlying-type同样,如果类型的name以大写开头,则会导出,可以在包外访问。可以简单地这样理解:命名类型决定能不能通过编译,而底层类型决定实际运行结果。举例:// 两种基于 float64 底层类型的新的命名类型type Celsius float64type Fahrenheit float64/

2021-11-09 20:28:46 830

原创 golang的指针

变量是值的名字或代号,指针是变量的地址。每个变量都有自己的地址。指针的本质是一个运算符(就像个函数一样),运算符的返回结果是内存地址。这个内存地址也可以赋值给一个指针类型的变量,如*int。对于指针类型的变量,有一个专属的操作符(*),返回值是某内存地址处存放的值。x := 1p := &x // &取内存地址,p就是一个 *int 类型的指针变量*p = 2 // *取内存地址指向的值fmt.Println(x) // 结果为2可以看出,借助指针,普通类型的变量也

2021-11-09 20:27:16 64

原创 golang的命名风格、声明、可见性和生命周期

可见性与scope如果在函数中声明,则仅在函数内有效;如果在函数外声明且小写开头,则在包内可见,即,在当前文件内可见,以及在同一个包内的其它源文件内可见;如果在函数外声明且大写开头,则设为export,对于包外可见和可用。没有所谓的public/private之类的关键字了。命名风格可见性越大,则命名可以越长越详细,可见性越小,命名越简单。使用驼峰命名法,例如 userName, 而不是 user_name。对于专用名词的缩写,常使用相同的大小写来表示,比如 htmlEscape,

2021-11-09 20:21:55 240

原创 如何使用VisualVM分析java快照

当我们遇到一些java运行期间的疑难问题时,比如占用内存过大或假死等现象,往往想到的是dump一个快照出来分析一下。今天用一个最简单的例子来分享一下我分析java快照的方法。代码实例我喜欢用最简单的分析问题,太复杂的代码有太多噪音。下面是一些非常简单的代码。package com.example;public class UserInfo { private String name; private String role; private int age;

2021-10-12 16:00:17 480

原创 jinfo的用法

jinfo命令比较简单,主要是用来查看和调整一些开关类的参数。使用方法如下:jinfo -flag :打印对应的启动参数的值jinfo -flag [+/-] :启用或禁用对应的启动参数jinfo -flag = :设置对应的启动参数的值使用场景举例:假设有一个java应用出问题了,你登上服务器想看看GC日志是否正常,结果发现java进程启动的时候没有开启PrintGC的开关,你可以通过下面的命令打开这个开关jinfo -flag +PrintGC <pid>如果没有

2021-10-12 15:43:32 963

原创 jstat的主要用法

jstat主要用来查看当前java进程的各内存区域的使用情况以及GC的次数和总耗时。我最常用的是下面的命令:jstat -gcutil <pid> [interval] [times]可以用[interval]来控制每隔多少毫秒重复输出一次,并通过[times]参数来控制输出的总次数。这两个参数都是可以省略的,如果都省略的话,就只输出一次。下面举例说明以下,输出pid=53560的java进程的内存各区域的利用率,每隔1000毫秒输出一次,共输出五次。$ jstat -gcutil 5

2021-10-12 15:41:19 647

原创 常见的GC算法介绍

本文涵盖几种常用的垃圾回收算法的简单介绍,包括:标记清除算法(Mark-Sweep)复制算法(Copying)标记压缩算法(Mark-Compact)分代算法(GenerationalCollecting)分区算法(Region)内容和截图全部来自《实战Java虚拟机:JVM故障诊断与性能优化(第2版)》标记清除算法(Mark-Sweep)标记清除法是现代垃圾回收算法的思想基础。标记清除法将垃圾回收分为两个阶段:标记阶段和清除阶段。在标记阶段,首先通过根节点标记所有从根节点开始的可达对

2021-10-09 18:14:50 184

原创 JVM常用参数的介绍

本文将分门别类地介绍一些常用的JVM的参数,包括:内存相关参数显示GC日志的参数类加载的相关参数显示启动参数的参数内存相关参数堆空间的配置-Xmx 指定堆内存的最大空间,设置方式:-Xmx<value>-Xms 指定堆内存的初始空间,设置方式:-Xms<value>oracle官方推荐将初始堆Xms与最大堆Xmx设置为相等。这样的好处是,可以减少程序运行时进行垃圾回收的次数,同时也减少了虚拟机需要做出决策的数量,这些可以提高程序的性能。我的经验是,如果ja

2021-10-08 17:03:58 72

原创 linux删除文件后磁盘没有释放

今天发现linux服务器满了,运行df -h,显示 /这个挂载已经满了。我通过 du -d 1 -h /,去寻找哪个目录占用空间比较大。我发现/usr 目录占用空间比较大,进而通过 du -d 1 -h /usr 去查看 /usr 目录下哪个目录占用的空间比较大,指导我找到一个或多个较大的文件。在linux服务器上通过 rm命令删除这些大文件。然后,通过du和df命令,发现磁盘并没哟释放。原来,通过rm并不一定会立刻完全删除文件,它还有可能被某个进展占用着。通过下面的命令,就可以找出是哪个进程还在

2021-09-26 11:04:58 469

原创 关于单元测试的思考

最近读了读《单元测试的艺术(第2版)》这本书,来谈谈我对单元测试的几点看法,然后再谈谈如何通过stub和mock的理念,隔离具体的依赖从而进行更纯粹的单元测试。单元测试的意义是什么我目前认为单元测试有以下几个意义:单元测试是保护网,告诉你修改的代码是否破坏了已有的功能,从而有效提高代码质量。(在《高效程序员的45个习惯》这本书中被称为守护天使)单元测试是一个可运行的文档。一般情况下,单元测试的逻辑比较清晰且不包含业务逻辑,所以通过阅读单元测试,可以更直接地了解代码的意图。单元测试可以促进代码的设

2021-09-18 17:19:01 95

原创 页面出现不必要的滚动条,怎么调试?

不知道你有没有遇到过这样的情况,明明一个网页上的内容不多,却出现了一个纵向的滚动条。有些强迫症的你,很想找出是哪个地方的height设置错了。如果你遇到过这样的问题,应该明白我在说什么。我今天就遇到了这样的问题。我的解决过程是这样的:按F12进入调试模式,从body下逐个尝试给组件加display: none 这个属性,如果滚动条还存在,那说明跟它没关系,直到找到那个外层的元素,然后不断用这种方法来尝试他的子元素,最终就是它的height有问题。...

2021-08-20 21:06:39 736 1

原创 在vue项目中使用less

less提供了可编程的css,包括以下机制,可以提高css代码的可维护性和可读性定义变量并多次使用mixins(一个样式中包含另一个样式)格式嵌套(可以形成代码块,有利于提高可读性)@import (可以将样式拆分到不同的文件中,形成组件)本篇主要来讨论如何在vue项目中使用less安装依赖包npm install -D less less-loader@7.3.0由于less-loader和webpack版本适配的问题,下面提供更多版本信息@vue/cli的版本$ vue --v

2021-08-20 16:30:08 12600

原创 熟练使用flex布局

flex是一种功能非常丰富的布局模式,是为了弥补已有的布局手段的短板。作为一种功能丰富的布局模式,它一口气解决以下全部问题:如何支持横向布局和纵向布局百分比模式的动态宽度和动态高度如何实现元素的排列方向和动态间距如何实现自动换行下面我们来逐个实现上面的所有场景。基础用法<div class="container"> <div class="item"></div> <div class="item"></

2021-08-20 12:06:41 1013

Sun Java System Application Server Performance Tuning Guide.pdf

Sun Java System Application Server Enterprise Edition 8.2 Performance Tuning Guide.pdf

2021-10-08

programming python.pdf

programming python.pdf 英文电子书

2017-08-29

[Unity.3D游戏开发].宣雨松.扫描版.pdf

[Unity.3D游戏开发].宣雨松.扫描版.pdf 电子书,本人亲自加上了详细的书签。

2013-11-19

锋利的JQuery电子版(带源码)

《锋利的JQuery》电子书,高清,带有详细的目录,另外,还有书中用到的源码。就需要付两分,不多哦。

2012-01-09

NorthWind数据库

这是两个数据库,一个是NorthWind,另一个是Pubs,两个都是经典的数据库。包含了mdf文件盒ldf文件,适合sql server 2005及其以上版本,直接附加就可以了。

2012-01-06

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除