数据同步
数据同步敬请期待……
架构五要素
架构五要素一般在做架构设计时,我们会关注以下五个要素:
高性能
高可用
伸缩性
扩展性
安全性
高性能性能的测试指标主要有:
响应时间:指应用执行一个操作需要的时间
并发数:指系统能够同时处理请求的数目
QPS:指单位时间内系统处理的请求量
系统性能计数器:描述服务器或者操作系统性能的一些数据指标
性能优化,根据网站分层架构,可以分为三大类:
Web前端性能优化
减少http请求
适用浏览器缓存
启用压缩
减少Cookie传输
应用服务器性能优化:缓存、集群、异步
多线程(设计为无状态,使用局部对象,并发访问资源使用锁)
资源复用(单例,对象池)
数据结构
异步操作(消息队列,削峰作用)
多台应用服务器组成一个集群共同对外服务,提高整体处理能力
使用CDN,将网站静态内容分发至里用户最近的网络服务器机房,使用户通过最短访问路径获取数据。可以在网站机房部署反向代理服务器,缓存热点文件,加快请求响应速度,减轻应用服务器负载压力
应用服务器端,可以使用服务器本地缓存和分布式缓存(网站性能优化第一定律:考虑使用缓存优化性能)
代码层面,通过使用多线程、改善内存管理等手段优化性 ...
缓存
缓存敬请期待……
负载均衡
负载均衡敬请期待……
集群技术
集群技术敬请期待……
高可用
高可用敬请期待……
HashMap的扩容机制
HashMap的扩容机制简介HashMap是单纯的kv键值对结构,可以接受null键和null值,速度比较快,非线程安全。
HashMap的数据结构HashMap实际上是一个“链表的数组”的数据结构,每个元素存放链表头节点的数组,即数组和链表的结合体。
Entry就是数组中的元素,每个Map.Entry其实就是一个key-value对,它持有指向下一个元素的引用,这就构成了链表。
工作原理
put
当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组的该位置上。
HashMap基于hashing原理,使用put()方法存储,当将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,然后找到bucket位置来存储值对象。
当获取对象时,同上找到对应的bucket,通过键对象的equals() ...
JDK并发包里常用的类
JDK并发包里常用的类资料:
并发编程 :Concurrent 用户指南 ( 上 )
并发编程 :Concurrent 用户指南 ( 中 )
并发编程 :Concurrent 用户指南 ( 下 )
ConcurrentHashMap是线程安全的。
put方法,首先是对key.hashCode进行hash操作,得到hash值。然后获取对应的segment对象,接着调用Segment对象的put方法完成当前操作。当调用put方法时,首先lock操作。完成操作后再释放锁。
http://ifeve.com/concurrenthashmap/
Semaphore可以控制某资源同时被访问的个数。例如连接池中通常要控制创建连接的个数。
tryAcquire方法,获得锁release方法,释放锁
CountdownLatch闭锁,确保一个服务不会开始,直到它依赖的其他服务都已经开始,它允许一个或多个线程,等待一个事件集的发生。通过减计数的方式,控制多个线程同时开始某个动作。当计数为0时,await后的代码才会被执行。提供await()和countDown()两个方法。
CyclicBarri ...
Java8函数式编程(lambda表达式)
Java8函数式编程(lambda表达式)简介面向对象编程是对数据进行抽象;函数式编程是对行为进行抽象。
核心思想:使用不可变值和函数,函数对一个值进行处理,映射成另一个值。
对核心类库的改进主要包括集合类的API和新引入的流Stream。流使程序员可以站在更高的抽象层次上对集合进行操作。
示例
Lambda 表达式的 10 个示例
learn-java8
java8-tutorial
一文让你明白lambda用法与源码分析
分类
惰性求值方法
1list.stream.filter(f -> f.getName().equals("p1"));
这行代码并未做什么实际性的工作,filter知识描述了Stream,没有产生新的集合。
如果使多个条件组合,可以通过代码块{}
及早求值方法
1List<Person> resultList = list.stream().filter(f -> f.getName().equals("p1")).collect(Collectors.toList());
c ...
Java关键字
Java关键字volatilevolatile是Java最轻量级的同步机制。
特性:
可见性。变量读写直接操作主存而不是CPU Cache。当一个线程修改了volatile修饰的变量后,无论是否加锁,其他线程都可以立即看到最新的修改。
禁止指令重排序优化。
保证变量可见性,但无法保证原子性。也就是说非线程安全。
Java内存模型:
详情可参考 深入分析volatile的实现原理
synchronized线程安全,锁区域内容一次只允许一个线程执行,通过锁机制控制。
当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它sy ...
Java多线程知识汇总(1)
Java多线程知识汇总(1)
引用自Java多线程知识小抄集(一)
interrupted与isInterrupted的区别
interrupted():测试当前线程是否已经是中断状态,执行后具有状态标志清除为false的功能。 isInterrupted():测试线程Thread对象是否已经是中断状态,但不清除状态标志。
方法:
1234567public static boolean interrupted() { return currentThread().isInterrupted(true);}public boolean isInterrupted() { return isInterrupted(false);}private native boolean isInterrupted(boolean ClearInterrupted);1234567
终止正在运行的线程的三种方法:
使用退出标志,是线程正常退出,也就是当run方法完成后线程终止; 使用stop方法强行终止线程,但是不推荐使用这个方法,因为 ...
Java多线程知识汇总(2)
Java多线程知识汇总(2)
引用自Java多线程知识小抄集(二)
ConcurrentHashMap
ConcurrentHashMap是线程安全的HashMap,内部采用分段锁来实现,默认初始容量为16,装载因子为0.75f,分段16,每个段的HashEntry<K,V>[]大小为2。键值都不能为null。每次扩容为原来容量的2倍,ConcurrentHashMap不会对整个容器进行扩容,而只对某个segment进行扩容。在获取size操作的时候,不是直接把所有segment的count相加就可以可到整个ConcurrentHashMap大小,也不是在统计size的时候把所有的segment的put, remove, clean方法全部锁住,这种方法太低效。在累加count操作过程中,之前累加过的count发生变化的几率非常小,所有ConcurrentHashMap的做法是先尝试2(RETRIES_BEFORE_LOCK)次通过不锁住Segment的方式统计各个Segment大小,如果统计的过程中,容器的count发生了变化,再采用加锁的方式来统计所有的Segmen ...
Java多线程知识汇总(3)
Java多线程知识汇总(3)
引用自Java多线程知识小抄集(三)
SimpleDateFormat非线程安全
当多个线程共享一个SimpleDateFormat实例的时候,就会出现难以预料的异常。
主要原因是parse()方法使用calendar来生成返回的Date实例,而每次parse之前,都会把calendar里的相关属性清除掉。问题是这个calendar是个全局变量,也就是线程共享的。因此就会出现一个线程刚把calendar设置好,另一个线程就把它给清空了,这时第一个线程再parse的话就会有问题了。
解决方案:1. 每次使用时创建一个新的SimpleDateFormat实例;2. 创建一个共享的SimpleDateFormat实例变量,并对这个变量进行同步;3. 使用ThreadLocal为每个线程都创建一个独享的SimpleDateFormat实例变量。
CopyOnWriteArrayList
在每次修改时,都会创建并重新发布一个新的容器副本,从而实现可变现。CopyOnWriteArrayList的迭代器保留一个指向底层基础数组的引用,这个数组当前位于迭代器的起 ...
Java多线程知识点
Java多线程知识点Java多线程相关的一些面试题。
线程和进程有什么区别?
一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。
如何在Java种实现线程?
创建线程有两种方式:1、继承 Thread 类,扩展线程。2、实现 Runnable 接口。
启动一个线程是调用run()还是start()方法?
启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM 调度并执行,这并不意味着线程就会立即运行。run()方法是线程启动后要进行回调(callback)的方法。
Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别?
sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程 ...
Java并发源码合集
Java并发源码合集
【死磕Java并发】—– 深入分析synchronized的实现原理
【死磕Java并发】—– 深入分析volatile的实现原理
【死磕Java并发】—– Java内存模型之happens-before
【死磕Java并发】—– Java内存模型之重排序
【死磕Java并发】—– Java内存模型之分析volatile
【死磕Java并发】—– Java内存模型之从JMM角度分析DCL
【死磕Java并发】—– Java内存模型之总结
【死磕Java并发】—– J.U.C之AQS:CLH同步队列
【死磕Java并发】—– J.U.C之AQS:同步状态的获取与释放
【死磕Java并发】—– J.U.C之AQS:阻塞和唤醒线程
【死磕Java并发】—– J.U.C之重入锁:ReentrantLock
【死磕Java并发】—– J.U.C之读写锁:ReentrantReadWriteLock
【死磕Java并发】—–J.U.C之Condition
【死磕Java并发】—- 深入分析CAS
【死磕Java并发】—- J.U.C之并发工具类:CyclicBarrier
【 ...
Java异常Exception
Java异常Exception捕获异常时需要注意 try、catch、finally 块中的控制转移语句。示例:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111public class TryCatchFinallySample { private static int testFinallyReturn() { int i = 1; try { return i; } catch (Exception e) { return i; & ...
Java的System.getProperty()方法使用
Java的System.getProperty()方法使用
引用自java的System.getProperty()方法使用
获取环境变量通过 System.getProperty("propertyName") 可以获得环境变量设置的值。
常见的Key值有:
key值
说明
java.version
Java 运行时环境版本
java.vendor
Java 运行时环境供应商
java.vendor.url
Java 供应商的 URL
java.home
Java 安装目录
java.vm.specification.version
Java 虚拟机规范版本
java.vm.specification.vendor
Java 虚拟机规范供应商
java.vm.specification.name
Java 虚拟机规范名称
java.vm.version
Java 虚拟机实现版本
java.vm.vendor
Java 虚拟机实现供应商
java.vm.name
Java 虚拟机实现名称
java.specifi ...
Linux IO模式及select、poll、epoll详解
Linux IO模式及select、poll、epoll详解
引用自Linux IO模式及 select、poll、epoll详解
本文讨论的背景是Linux环境下的network IO。
概念说明用户空间与内核空间现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方)。操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操心系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。针对linux操作系统而言,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间。
进程切换为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行。这种行为被称为进程切换。因此可以说,任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关的。 ...
NIO介绍
NIO介绍
引用自NIO介绍
简介NIO时Java 1.4引入的新特性。是对原来的Standard IO的扩展。
Standard IO时对字节流的读写,在进行IO之前,首先创建一个流对象,流对象进行读写操作都是按字节,一个字节一个字节的读或写。而NIO把IO抽象成块,类似磁盘的读写,每次IO操作的单位都是一个块,块被读入内存之后就是一个byte[],NIO一次可以读或写多个字节。
组件Selector多路复用选择器,基于“事件驱动”,其核心就是通过Selector来轮询注册在其上的Channel,当发现某个或多个Channel处于就绪状态后,从阻塞状态返回就绪的Channel的SelectionKey集合,进行I/O操作。
创建多路复用器并启动线程
12Selector selector = Selector.open();new Thread(new ReactorTask()).start();
创建Channel
123456789//打开ServerSocketChannel,用于监听客户端的连接ServerSocketChannel ssc = Ser ...
Netty长连接服务
Netty长连接服务
引用自Netty 长连接服务
Netty是什么Netty: http://netty.io/
Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.
官方的解释最精准了,期中最吸引人的就是高性能了。但是很多人会有这样的疑问:直接用 NIO 实现的话,一定会更快吧?就像我直接手写 JDBC 虽然代码量大了点,但是一定比 iBatis 快!
但是,如果了解 Netty 后你才会发现,这个还真不一定!
利用 Netty 而不用 NIO 直接写的优势有这些:
高性能高扩展的架构设计,大部分情况下你只需要关注业务而不需要关注架构
Zero-Copy 技术尽量减少内存拷贝
为 Linux 实现 Native 版 Socket
写同一份代码,兼容 java 1.7 的 NIO2 和 1.7 之前版本的 NIO
Poole ...