自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(54)
  • 资源 (2)
  • 问答 (2)
  • 收藏
  • 关注

原创 Java面试系列-spring相关

Spring中的Bean是线程安全的吗?Spring 中的 bean 默认都是单例的,所有线程都共享一个单例实例Bean,因此是存在资源的竞争,是线程不安全的。但是spring中大部分bean都是在方法内部操作,例如:Controller、Service、Dao等,不会对bean的成员变量做查询以外的操作,这种bean是线程安全的。如果非要在这些bean中定义成员变量并修改它,可以声明@Scope("prototype")保证线程安全。在spring内部有一些bean会对成员变量操作,例如:Reque

2021-01-25 11:03:31 157

原创 Java面试系列-redis相关

redis是个啥东西?redis全称是“Remote Dictionary Service”(远程字典服务),在互联网领域,它是使用最广泛的缓存中间件,大部分公司或多或少的都会使用到redis,它不仅可以用作缓存,还可以有很多其他用途,如分布式锁、接口的幂等性等。redis有哪些数据结构?redis有五种基础数据结构,分别是:string(字符串)、list(列表)、hash(字典)、set(集合)、zset(有序集合)。具体各个数据结构的用途可以回看我以前的文章:传送门string(字符串):

2021-01-25 11:02:01 193

原创 聊聊Redis的持久化

redis:我的数据不仅可以放在内存中,照样可以持久化到硬盘中。所以我也是一种数据库。我们都知道,redis就是靠快而出名,而它的快则是因为数据全部在内存中操作。但是如果数据仅仅只放在内存中的话,还是有问题的,比如服务宕机、机器重启等都会造成内存数据丢失,因此,必须使用某种方法将redis数据持久化到硬盘中。redis采用了两种持久化方式:RDB和AOF。RDBRDB是一种快照技术,快照是一次全量备份,它是将内存数据全部以二进制形式保存下来,且内容非常紧凑。我们都知道,redis的快还有一个.

2021-01-25 10:59:14 177

原创 Java面试系列-线程相关(一)

实现多线程的方式继承Thread类,重写run方法,调用start方法启动线程实现Runnable接口,重写run方法,调用start方法启动线程实现Callable接口,重写call方法,并用FutureTask包装,在new Thread中传入FutureTask,然后调用start方法启动线程使用线程池保证线程安全的方式synchronized关键字实现的同步方法或者同步代码块ReentrantLock等实现的锁机制volatile关键字实现的变量线程安全使用AtomicInt

2021-01-25 10:54:41 96

原创 启动dubbo admin

下载源码:https://github.com/apache/dubbo-admin.git编译:mvn clean package -Dmaven.test.skip=true运行:mvn --projects dubbo-admin-server spring-boot:run浏览器访问:http://localhost:8080/

2020-12-15 16:36:30 153

原创 ThreadLocal解析

你们有没有经历过这种痛苦:很多方法一层一层调用,每次调用都要传相同的参数。这个时候就可以使用ThreadLocal来解决你的烦恼。ThreadLocal是什么?ThreadLocal表示的是线程本地变量,也可以说是每个线程都有同一个变量的独有拷贝。这个听上去可能不是那么好理解,我们先来看一下它能是怎么用的。ThreadLocal的使用在ThreadLocal中,我们经常使用的就下面三个方法:public void set(T value)public T get()public void .

2020-09-30 16:12:16 131

原创 Java到底是引用传递还是值传递

前言前段时间在群里看到类似这样一个问题,下面的代码会输出什么呢?public void test() { String str = "hello"; change(str); System.out.println(str);}private void change(String str) { str = "world";}当时看到这题,瞬间勾起了我的回忆。遥想当年,也曾经碰到过类似的问题,当时研究了好久才搞明白,这里再记录一下这个问题的思路。先来说一下答案:输出:he

2020-09-11 17:28:14 2596 3

原创 数据库索引

什么是索引?索引就跟我们的字典目录一样,如果一本字典没有目录,那么你要找一个字,那就相当费劲,得从头一点一点的找;在数据库中也是一样,如果一张表没有索引,那查询一条数据也是相当费劲。索引是啥样的?我们都知道,在数据库中的表数据都是一行一行的,但是如果给它加上索引(如果有主键,就会自动生成主键索引),它会变成啥样呢?这里以最常见的B+树索引为例,表结构会变成树状,像下面这样:索引的分类索引一般分为两个大类:聚集索引和非聚集索引。我们平时使用的主键索引就是聚集索引,一张表最多只能有一个聚集索引;而平

2020-08-03 10:59:27 131

原创 事务的隔离级别

事务的隔离级别数据库一般有四种特性:原子性、一致性、隔离性和持久性。而数据库的隔离级别就是针对其中的隔离性而言。隔离级别也有四种:未提交读、提交读、可重复读、串行化。也不是所有数据库都支持事务的,甚至同一数据库不同存储引擎事务都不是一样的,例如MySQL数据库,里面InnoDB 引擎支持事务,而MyISAM 引擎不支持事务。而在我们应用层面,例如spring框架基于数据库事务的隔离级别也提供了自己的隔离级别,它有五种,其中四种和数据库一一对应,还有一种是DEFAULT,它表示使用数据库默认的隔离级别。

2020-08-03 10:58:10 112

原创 并发编程之线程协作

在谈论到多线程的时候,大部分都是线程之间资源竞争,但是也有时候,线程之间也是需要相互协作的。此文我们就来探讨一下线程之间是如何协作的?wait/notify(等待通知)首先要知道 wait和notify/notifyAll都是Object的方法,而不是Thread的方法,这使得每个对象都能调用这几个方法。上回谈到synchronized加锁的时候,每个对象都有一把锁,是通过对象头来实现的,而且对象还有一个等待队列,当线程获取不到对象锁的时候,会进入等待队列。除此之外,对象还有另外一个等待队列,这是个.

2020-08-03 10:55:30 156

原创 spring事务的传播机制

什么是事务?数据库事务是指一系列严密操作,要么全部成功,要么全部失败。它有四种特性:原子性、一致性、隔离性和持久性。而spring事务是封装在数据库事务之上的一种事务处理机制,它有两种管理方式:编程式事务和声明式事务。在平时使用中,我们大多使用@Transactional声明式事务来管理,这也是spring推荐的方式,下面例子也统一采用此种方式。下面我们主要来看看spring事务的传播机制spring事务的传播机制spring事务的传播机制有七种:REQUIRED、REQUIRES_NEW、NES

2020-08-03 09:41:24 6220

原创 数据是怎么一步一步到服务器的

当我们在浏览器输入www.baidu.com,回车以后,是怎么显示百度页面的?首先通过DNS查询IP首先我们要知道查询服务器都是通过IP来查找的,那么第一步就要查询www.baidu.com这个域名对应的IP是什么,这时候就需要去查询DNS服务器,那这个DNS服务器的地址我们怎么知道呢?一般DNS服务器地址可以自动获取或者手动设置DNS服务器地址知道了,那浏览器是怎么去查DNS服务器的呢?这就需要调用Socket库,里面封装了通过域名查询IP的方法,这个方法里具体做了什么,我们后面再说,注意一点.

2020-06-19 08:32:08 1183

原创 redis分布式锁

前言上回说到如何使用zookeeper实现分布式锁,它是通过节点的新建和删除来实现的,这种频繁的io操作在并发很高的情况下肯定是不适用的,那这节我们来看看如何使用redis实现分布式锁。我们都知道redis最大的优势就是速度快,大部分操作都是在内存中直接完成的,这就和io操作不在一个数量级上了。手动实现分布式锁实现逻辑首先我们要理清redis实现分布式锁的逻辑:在redis中,我们主要通过setnx这个命令来实现分布式锁,这个命令什么意思呢?set not exit,只有在key不存在时,才会设值

2020-06-19 08:30:29 179

原创 手摸手教你搭建免费图床

使用Gitee搭建免费图床Gitee是一个类似于GitHub的国内网站,至于为什么用Gitee搭建图床而不用Github,就是因为他快,毕竟GitHub是国外网站,如果没有点科学上网的手段,那网速慢得怀疑人生。下面一步一步带你们使用Gitee搭建自己的图床。第一步 新建Gitee仓库如果没有gitee账号,可以先注册一个,然后新建仓库仓库名称自己定义,是否开源选择公开,然后选择Readme初始化这个仓库。第二步 创建令牌先进入设置页面左侧菜单选择私人令牌然后点击生成新令牌然后点

2020-06-19 08:29:16 445

原创 zookeeper分布式锁

前言前面并发章节中提到各种锁来防止并发带来的异常结果,但是这都是在单机情况下才奏效,如果在分布式情况下,就要采用分布式锁了,分布式锁的实现有很多种,主要有zookeeper和redis分布式锁,此章先说说zookeeper怎么实现分布式锁。分布式锁实现前面提到zookeeper的搭建和客户端操作,我们在这基础上来实现一下分布式锁。zookeeper主要是各种节点,要实现分布式锁可以用创建节点和删除节点来实现,但是创建什么样的节点呢?前面提到zookeeper有四种节点,其中的顺序节点就可以模拟各个线

2020-06-19 08:26:52 142

原创 zookeeper的Java客户端操作

客户端选择zookeeper的Java客户端主要有zkclient和Curator,此篇文章介绍Curator,就冲他官网的简介,zookeeper书的作者Patrick Hunt给了这么高的评价:Guava is to Java what Curator is to Zookeeper。实际操作下来,Curator确实比zkclient更全面,代码编写也更加优雅。引入jar包Curator主要提供了三个包curator-framework:对zookeeper操作的封装curator-cl

2020-06-19 08:25:57 1020

原创 zookeeper伪集群搭建

伪集群伪集群就是在一台机器上启动多个相同应用,模拟真实集群环境。zookeeper的伪集群步骤和真实集群基本一样,只是配置的IP端口有点区别。为什么需要集群?在生产环境中,不论什么单体应用都不能保证一直可用,比如服务宕机,云厂商出现的bug或者物理机器遇到的天灾人祸这些,虽然概率小,但是也不能完全避免。为了实现高可用,就需要集群,同一应用多地部署,就算其中一个挂了,其他的也能继续提供服务。zookeeper对集群的要求zookeeper集群节点数必须是奇数,因为在zookeeper集群中,需要一个

2020-06-19 08:25:08 167

原创 Java动态代理

代理模式是23种设计模式中最重要的模式之一,在Java中使用非常广泛,Mybatis、spring等框架中也都有它的身影。什么是代理?代理背后一般至少有一个真实对象,代理的外部功能和真实对象一般是一样的,用户与代理打交道,不直接和真实对象接触。另外两种设计模式(适配器和装饰器)和代理模式有点类似,不同之处在于,适配器是提供了一个不一样的新接口,装饰器是对原接口起到了装饰作用,可能是增加了新接口、修改了原有的行为等,而代理一般不改变接口。静态代理静态代理比较简单,如下:public class .

2020-06-19 08:22:58 96

原创 spring中的发布订阅

发布订阅模式可能大家都熟悉,消息队列、redis等很多中间件都有发布订阅模式,但你知道我们平时用的spring也有发布订阅模式吗?在我们系统中,可能会遇到处理完一个流程以后,接下来要同时处理多个流程,比如用户支付成功以后,接下来会同时减少库存、发送下单成功短信等,这种情况就可以用到发布订阅。减少库存和发送下单成功短信服务监听支付成功事件,当用户支付成功以后,发布这个消息,另外两个服务则会监听到,接着执行对应的逻辑。可能在真实情况下,我们应用都是分布式的,处理这种情况可能都是使用消息队列等中间件来处理.

2020-06-19 08:20:58 2016 2

原创 自定义注解实现日志记录

前言平时开发中,我们经常需要通过日志或者数据库来记录系统中一些重要的操作,如删除、修改和新增等。但每次在这些方法里手动打印日志或者记录到数据库有点不现实,像这种统一的操作可以使用spring中的AOP来实现,但是使用AOP切到包或者某种类的话,那只能记录这个包或类下面的日志,不易扩展,这时候就需要自定义注解,然后使用AOP切到这个注解上就行了。自定义注解自定义注解首先要知道元注解,也就是注解的注解,是jdk内置的。元注解有四种:@Retention 注解保留策略@Retention(Ret

2020-06-19 08:19:36 2815

原创 一文搞懂NIO

前言前面说过Java中的IO操作,但是传统的IO是阻塞模式的,在高并发的系统中肯定是不可行的,这次我们来介绍Java中提供的另外一种IO操作–NIO。首先,我们要知道应用程序中的IO和操作系统的IO是有区别的,应用程序的IO最终都需要依靠操作系统的IO来完成最终的操作。这时候就需要选择合适的IO模型,常见的IO模型有四种:同步阻塞IO(Blocking IO)阻塞IO指的是需要内核IO操作彻底完成后,才能继续执行下面的操作。Java中传统的IO和socket默认都是同步阻塞IO同步非阻塞I

2020-06-19 08:15:00 198

原创 一文搞懂IO流

前言io流在Java的知识体系中,属于很杂的那种了,主要是涉及的类太多,输入流、输出流、文件输入流、文件输出流、字节输入流和输出流、字符输入流和输出流等等,经常把人弄晕。但是它的用途却非常广泛,文件的操作、网络的操作等都离不开它,本文通过平时常用操作来梳理一下io流中涉及的重要类及方法。什么是流在Java中,文件一般不是单独处理的,而是视为输入输出设备的一种,Java使用一个统一的概念来处理所有的输入输出,包括键盘输入和网络输入输出等。这个统一的概念就是流,流又分为输入流和输出流,InputStrea

2020-06-19 08:11:48 440 1

原创 解决IDEA2020控制台乱码

以前使用idea2019版本时,控制台乱码都是修改这两处来解决1、idea安装的bin目录下找到这两个文件这两个文件最后一行添加上 -Dfile.encoding=UTF-82、idea中tomcat配置上添加 -Dfile.encoding=UTF-8这样基本就可以解决了。但是今天换成idea2020以后,这样修改,控制台还是乱码,发现tomcat启动日志都乱码,这时候就需要改tomcat配置找到tomcat配置文件 conf/loggin.properties找到此处,原来这三处都

2020-06-03 17:50:08 3800

原创 ConcurrentHashMap

jdk1.7的ConcurrentHashMapjdk1.7采用的是Segment+HashEntry数组+链表来实现的ConcurrentHashMap初始化时有16个Segment,每个Segment中又包含了HashEntry数组,每个HashEntry又是一个链表,可以看出,Segment的结构和HashMap类似,你可以这样理解:ConcurrentHashMap由多个HashMap组成。线程安全的实现原理ConcurrentHashMap中的Segment在实现上继承了Reentran

2020-05-27 08:22:04 286

原创 jdk1.8HashMap

HashMap底层的数据结构HashMap底层是一个hash表加链表结构,jdk1.7以后,链表长度达到阈值(8)以后会转成红黑树。下面我们通过源码看看HashMap的底层实现。源码解析这里主要分析两个重要方法:put()和resize()方法put()方法public V put(K key, V value) { return putVal(hash(key), key, value, false, true);}put()方法中会将key的hash值传入到putVal()方

2020-05-27 08:18:01 109

原创 jdk1.7HashMap的问题

jdk1.7的HashMapHashMap从jdk1.8以后有较大改动,主要有两点:插入元素改成尾插法(1.7是头插法)链表长度超过8个转成红黑树(1.7一直是链表)jdk为何会做这两点改变呢?下面我们通过1.7的源码来看看这两点有什么问题或者不足之处头插法改成尾插法我们先来看看jdk1.7HashMap中插入元素的源码public V put(K key, V value) { if (key == null) return putForNullKey(valu

2020-05-27 08:15:13 476

原创 Future异步执行

前言随着业务的发展,系统的功能也越来越多,这时候很多业务操作就需要异步执行,提高效率。大多时候,我们都可以采用线程池来实现异步执行的需求,但是,有时候主流程需要等待其他任务执行完以后才能继续执行,又或者是主流程需要知道其他任务执行的结果,这时候,就需要采用线程的合并了。在讲线程合并之前,我们先来看看平时使用Thread是怎么实现主线程等待其他线程的。join合并线程当一个线程需要等待其他线程执行完再继续执行的时候,我们可以使用join或者是CountDownLatch,这里只说join,CountD

2020-05-26 08:28:56 706

原创 优雅的创建线程池

手动创建线程平时开发中经常会碰到需要用异步方式来实现某个需求,这时首先会想到这种写法new Thread(new Runnable() { @Override public void run() { System.out.println("to do something"); }}).start(); 或者用lambda简写new Thread(()-> System.out.println("to do something")).start();

2020-05-26 08:27:54 415 1

原创 共享锁

共享锁和独占锁共享锁:允许多个线程同时获取锁,如Semaphore,CountDownLatch,ReadLock等。独占锁:每次只能一个线程持有锁,如ReentrantLock,synchronized,WriteLock等。AQS中实现共享锁AQS中提供了独占锁和共享锁。独占锁使用acquire和release方法实现;共享锁使用acquireShared和releaseShared实现。下面我们看看源码中共享锁具体怎么实现的,以Semaphore和CountDownLatch为例Sema

2020-05-26 08:26:31 436

原创 volatile解析

volatile是java提供的一种轻量级的同步机制,可以理解为一个变量的同步锁。相比于重量级锁synchronized而言,synchronized大部分时候都是锁的方法或者代码块,而volatile只是锁一个变量,所以volatile更加轻量,当然现在jdk对synchronized的性能越来越优化,也没有想象中的那么重,在平时需要保证一个方法线程安全时,可以放心的使用synchronized。原理计算机系统在进行计算时,cpu会从内存中读取数据缓存在自己的寄存器(cpu中空间很小的一块内存空间,方

2020-05-26 08:25:21 130

原创 ReentrantLock解析

ReentrantLock(重入锁),利用AQS实现的一种可重入锁,和synchronized功能类似,但是synchronized有的它都有,synchronized没有的它还有。实现原理重入性线程获取锁的时候,如果已经获取锁的线程就是当前线程的话,则此线程直接再次获取成功。由于锁会被获取n次,则在释放锁的时候也要释放n次,才算释放成功。公平锁和非公平锁ReentrantLock在构造函数中提供了是否公平锁的初始化方法,默认是非公平锁。非公平锁的效率要远远高于公平锁,一般我们没有特殊需求的话都是

2020-05-26 08:21:51 103

原创 synchronized解析

synchronized是jvm级别的一种重量级锁,但是随着jdk对synchronized的不断优化,现在它已经变得没有我们想象的那么重了。由于synchronized使用简单,也不用手动释放锁,因此我们平时开发中用到最多的锁就是它了。synchronized锁的三种形式普通方法:锁是当前对象实例静态方法:锁是当前类的Class对象同步方法块:锁是synchronized括号里的对象实现原理同步代码块在编译后会在前后分别插入monitorenter和monitorexit指令,每个对象在同

2020-05-26 08:10:05 148

原创 CAS解析

CAS:compare and swap,也有的叫做 compare and set;意思都差不多,翻译过来就是比较并交换或者比较并设值。CAS包含三个值,内存地址(V),预期值(A),新值(B)。先比较内存地址的值和预期的值是否相等,如果相等,就将新值赋在内存地址上,否则,不做任何处理。这种是乐观锁的思想。源码解析CAS操作在JUC中大量用到,在解析AQS那章中,我们也有提到。再回头看一下AQS中CAS的操作protected final boolean compareAndSetState(i

2020-05-26 08:08:30 386

原创 AQS解析

解释AQS:全称“AbstractQueuedSynchronizer”,直译过来是抽象的队列同步器,一般我们把它叫做AQS,java中大部分并发类都是通过它来实现线程同步。它内部定义了一个变量(volatile int state)和一个等待队列,前者表示加锁状态,后者在多线程情况下争用资源时被阻塞会进入等待队列。源码解析volatile int statevolatile 是一个关键字,在并发处理中也经常会用到,后面单独用一篇文章介绍。(已去除源码中的注释,方便阅读)private vola

2020-05-26 08:04:42 104

原创 对象的内存分布和访问

对象的内存布局对象在内存中存储的布局分为3块区域:对象头、实例数据和对齐填充。对象头包括两部分信息第一部分官方称作“Mark Word”,用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID和偏向时间戳等。考虑到虚拟机的空间效率,Mark Word被设计成一个非固定的数据结构以便在极小的空间内存储尽量多的信息,它会根据对象的状态复用自己的存储空间。...

2020-03-06 16:39:44 808

原创 类加载机制(2)-双亲委派模型

类加载器虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类,实现这个动作的代码模块称为“类加载器”。对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器都拥有一个独立的类名称空间。例如:比较两个类是否“相等”,只有在这个类是由同一个...

2020-02-28 10:14:38 736

原创 Java内存结构

运行时数据区域Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。Java虚拟机所管理的内存包括如下几个部分:程序计数器程序计数器是一块较小的空间,它可以看作是当前线程所执行的字节码的行号指示器。由于Java虚拟机的多线程是通过线程轮流切换并分配处理其执行时间的方式来实现的,在任何一个确定的时刻,一个处理起都只会执行一条线程中的指令。因此为了线程切换后能恢...

2020-02-22 20:31:55 745

原创 类加载机制

定义虚拟机把描述类的数据从Class文件中加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。生命周期类从被加载到虚拟机内存开始,到卸载出内存为止,整个生命周期包括:加载、链接、初始化、使用、卸载,其中链接又包括验证、准备、解析。类的初始化虚拟机规范严格规定了有且仅有5种情况必须立即对类进行初始化:遇到new,get...

2020-02-22 10:42:58 258

原创 linux常用命令

文件相关find(文件查找)#查找根目录及子目录下所有以.txt结尾的文件find / -name "*.txt"#查找当前目录及子目录下所有以.txt或者.pdf结尾的文件find . -name "*.txt" -o -name "*.pdf"#查找当前目录及子目录下所有文件路径包含nginx的文件find . -path "*nginx*"whereis(查找二进制程...

2020-01-15 15:35:28 855

原创 不要到处都用@Autowired啦

相信大部分人项目只要用了spring框架,肯定到处都是@Autowired。注意: spring4.3以后就可以省略@Autowired了,全部更新内容: 地址;其中跟新内容如下这是什么意思呢,翻译过来“如果目标bean只定义一个构造函数,则不再需要指定@autowired注释。”;我们平时开发中的bean大部分都不写构造函数,系统默认一个无参构造函数,这就符合这一条件。此时helloS...

2019-10-18 16:12:24 3236 5

xshellplus.rar

xshellplus包含xhell和xftp,方便连接服务器和文件传输,内含注册码。

2019-05-29

instantclient_11_2.rar

oracle轻量客户端,navicat连接oracle数据库时需要配置,工具>选项>环境指向此工具中oci.dll

2019-05-29

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

TA关注的人

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