问题
没事做了个定时任务,定时给自己发邮件提示某些接口获取到的信息,结果本地调试正常,发到服务器上发现都是发送邮件超时
1 | 发送邮件报错:Could not connect to SMTP host: smtp.qq.com, port: 25 |
解决方案
修改发送端口,阿里 和腾讯都把25 端口关闭了.发送需要使用其他端口. 465
1 | properties.setProperty("mail.smtp.auth", "true");//开启认证 |
1 | mail: |
没事做了个定时任务,定时给自己发邮件提示某些接口获取到的信息,结果本地调试正常,发到服务器上发现都是发送邮件超时
1 | 发送邮件报错:Could not connect to SMTP host: smtp.qq.com, port: 25 |
修改发送端口,阿里 和腾讯都把25 端口关闭了.发送需要使用其他端口. 465
1 | properties.setProperty("mail.smtp.auth", "true");//开启认证 |
1 | mail: |
原因分析:
翻译过来就是:在请求目标中发现无效字符。有效字符在RFC 7230和RFC 3986中定义。
百度看看:原来这是从7.0开始的高版本tomcat中的新特性:就是严格按照 RFC 3986规范进行访问解析,而 RFC 3986规范定义了Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符(RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ])。
解决方案:
既然知道原因了,那我们应该怎么解决这个问题呢?
网上的几种办法:
1、更换低版本的Tomcat。这个办法表面上是可行的,但是这不是属于自欺欺人嘛。因为在实际的项目开发中,你改动Tomcat很可能也要改动JDK版本和其他jar包版本,这会影响到整个项目的正常开发,没理由大家都跟着你改吧。所以pass掉了。
2、在Tomcat的安装目录中,打开conf/catalina.properties,找到末尾的一行。增加两行配置:
tomcat.util.http.parser.HttpParser.requestTargetAllow=|{}
org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true
还是不行, 换toncat 这个 8.5 的有问题 ,8.0的就没问题了
什么是反射?
反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
1 | public class Apple { |
1 | java.lang.NullPointerException |
可以看到异常堆栈指出了异常在 Method 的第 497 的 invoke 方法中,其实这里指的 invoke 方法就是我们反射调用方法中的 invoke。
1 | <bean class="com.chenshuyi.Apple"> |
当我们在 XML 文件中配置了上面这段配置之后,Spring 便会在启动的时候利用反射去加载对应的 Apple 类。而当 Apple 类不存在或发生启发异常时,异常堆栈便会将异常指向调用的 invoke 方法。
从这里可以看出,我们平常很多框架都使用了反射,而反射中最最终的就是 Method 类的 invoke 方法了。
那么Method 的 invoke 方法做了什么呢?
1 |
|
开始是进行了一些权限的检查,最后是调用了 MethodAccessor 类的 invoke 方法进行进一步处理
反射:
1 | 1 Java反射机制主要功能: |
####创建对象的两种方法
Class 对象的 newInstance()
使用 Class 对象的 newInstance()方法来创建该 Class 对象对应类的实例,但是这种方法要求该 Class 对象对应的类有默认的空构造器。
调用 Constructor 对象的 newInstance()
先使用 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的 newInstance()方法来创建 Class 对象对应类的实例,通过这种方法可以选定构造方法创建实例。
1 | //获取 Person 类的 Class 对象 |
##基础
###类
抽象类与普通类的唯一区别就是不能创建实例对象和允许有abstract方法。
一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就可以认为是抽象类
抽象类可以有构造方法,接口中不能有构造方法。(构造方法,日常初始化数据的那个)
native作用:通知虚拟机,我要调用外部代码了(一般是c或者c++)
###异常
try {}里有一个return语句,什么时候执行finally{}?在执行return后,他继续执行finally,return的结果是没有执行finally前的。
运行时异常与一般异常有何异同?异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。
Servlet的生命周期包括 加载 、 实例化 、初始化、处理请求、服务结束。这个生存期由javax.servlet.Servlet接口的init(),service()和destroy方法表达。
request.getAttribute()和 request.getParameter()
getParameter()取得是通过容器的实现来取得通过类似post,get等方式传入的数据;
setAttribute()和getAttribute()只是在web容器内部流转,仅仅是请求处理阶段;只有先用setAttribute()设置之后,才能够通过getAttribute()来获得值,它们传递的是Object类型的数据
getAttribute是返回对象,getParameter返回字符串
**jsp有哪些内置对象?作用分别是什么?**JSP共有以下9个内置的对象:
1 | request 用户端请求,此请求会包含来自GET/POST请求的参数 |
JDBC访问数据库的基本步骤 加载驱动,通过DriverManager获取连接对象,通过连接对象获取会话,通过会话进行数据的增删改查,封装对象,关闭连接
JDBC编程中处理事务
1 | conn.setAutoComit(false);设置提交方式为手工提交 |
数据库连接池的原理。为什么要使用连接池。
创建连接费时,所以统一创建,多个操作共享同一连接。使用连接池可以提高对数据库连接资源的管理。基本思想是为数据库连接建立“缓冲池”,创建几个连接在缓冲区,调用时获取缓冲池,用完再放回去。
脏读,幻读问题 脏读:数据为读取到了还没持久化,可能进行回滚的数据。幻读:表示在使用事务过程中,多次查询一条数据得到的结果不同。解决方案都是使用事务隔离级别配置。
JDBC的DriverManager用来做什么JDBC的DriverManager是一个工厂类,用来创建连接,当Driver类被加载,会自动注册到工厂中。
execute,executeQuery,executeUpdate的区别
Statement的execute(String query)方法用来执行任意的SQL查询,如果查询结果是一个ResultSet,这个方法就返回true。如果不是ResultSet,比如insert或者update查询,它就会返回false。
Statement的executeQuery(String query)接口用来执行select查询,并且返回ResultSet。即使查询不到记录返回的ResultSet也不会为null。我们通常使用executeQuery来执行查询语句。如果传insert或者update会抛异常。
Statement的executeUpdate(String query)方法用来执行insert或者update/delete(DML)语句,或者 什么也不返回,对于DDL语句,返回值是int类型,如果是DML语句的话,它就是更新的条数,如果是DDL的话,就返回0。
只有当你不确定是什么语句的时候才应该使用execute()方法
JDBC的ResultSet是什么ResultSet对象维护了一个游标,指向当前的数据行。开始的时候这个游标指向的是第一行。如果调用了ResultSet的next()方法游标会下移一行,如果没有更多的数据了,next()方法会返回false。可以在for循环中用它来遍历数据集。
Get与Post 按HTTP规范来讲,Get用于信息获取,应该是幂等的,Post用于数据修改提交等。但是多数开发情况下,Get也用作提交了,写起来方便。Get最多提交1014个字节
###泛型
Java中的泛型是什么 ? 使用泛型的好处是什么参数化类型,也就是说所操作的数据类型被指定为一个参数。1、类型安全,提供编译期间的类型检测 2、前后兼容 3、泛化代码,代码可以更多的重复利用 4、性能较高,用GJ(泛型JAVA)编写的代码可以为java编译器和虚拟机带来更多的类型信息,这些信息对java程序做进一步优化提供条件。
Struts其实就是个Servlet,已经多年没人用了。
Hibernate 对象关系映射,坑爹的缓存
使用Hibernate的基本流程是:配置Configuration对象、产生SessionFactory、创建session对象,启动事务,完成CRUD操作,提交事务,关闭session。
行级锁
开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
表级锁
开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。
页级锁
页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁.表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。BDB支持页级锁
MyBatis中使用#和$书写占位符有什么区别?
#将传入的数据都当成一个字符串,会对传入的数据自动加上引号;
$将传入的数据直接显示生成在SQL中。
注意:使用$占位符可能会导致SQL注射攻击,能用#的地方就不要使用$,写order by子句的时候应该用$而不是#。
MyBatis中的动态SQL
1 | MyBatis中用于实现动态SQL的元素主要有: |
JDBC编程有哪些不足之处,mybatis如何优化**
JDBC连接频繁创建,mybatis在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接
JDBC代码混写,mybatis在XXXXmapper.xml文件中与java代码分离
JDBC解析麻烦,mybatis自动映射java对象
MyBatis的一级缓存和二级缓存?
Mybatis首先去缓存中查询结果集,如果没有则查询数据库,如果有则从缓存取出返回结果集就不走数据库。Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象
Mybatis的二级缓存即查询缓存,它的作用域是一个mapper的namespace,即在同一个namespace中查询sql可以从缓存中获取数据。二级缓存是可以跨SqlSession的。
iBatis与Hibernate
相同点:屏蔽jdbc api的底层访问细节,使用我们不用与jdbc api打交道,就可以访问数据。
ibatis的好处:屏蔽jdbc api的底层访问细节;将sql语句与java代码进行分离;提供了将结果集自动封装称为实体对象和对象的集合的功能,queryForList返回对象集合,用queryForObject返回单个对象;提供了自动将实体对象的属性传递给sql语句的参数。
Hibernate是一个全自动的orm映射工具,它可以自动生成sql语句,ibatis需要我们自己在xml配置文件中写sql语句,hibernate要比ibatis功能负责和强大很多。但是对于复杂sql,batis更好写。
Hibernate的二级缓存
缓存的作用是可以快速查询,减少数据库压力。Hibernate的Session就是一种缓存,通常将之称为Hibernate的一级缓存,使用session从数据库中查询出一个对象时,Session也是先从自己内部查看是否存在这个对象,存在则直接返回,不存在才去访问数据库,并将查询的结果保存在自己内部。Hibernate的二级缓存就是要为Hibernate配置一种全局缓存,让多个线程和多个事务都可以共享这个缓存。我们希望的是一个人使用过,其他人也可以使用,session没有这种效果。
###其他
单例模式
单例的类别:懒汉、饿汉、枚举、静态内部类、双重校验锁 等等 , 选择线程安全我选最后一种,双重校验锁。
int强转byte会如何?可以强转,但是int是32位的,byte是8位的,导致,强转后,int的高24位会丢失只会保留后低8位
a.hashCode() 有什么用?与 a.equals(b) 有什么关系? hashCode() 方法对应对象整型的 hash 值。两个使用 equal() 方法来判断相等的对象,必须具有相同的 hash code。
i18n 国际化,多套语言模板。
生产者——消费者 问题
日常使用队列存就好了,然后获取,如果队列满了。就找个地方存呗,当队列处理完后,获取存储内容即可。
哲学家进餐
谈谈你对NIO的理解
答:IO是面向流,NIO是面向缓冲 ,这里不细讲了,具体参照:Java NIO和IO的区别
io是面向流的,nio面向的是缓冲区
io是直接读取一个或多个字符,知道全部读完,没有缓存,不能前后移动流中的数据.阻塞的
nio可以前后移动了,非阻塞,
程序计数器(线程私有):当前线程所执行字节码的行号指示器。
Java 虚拟机栈(线程私有): 为虚拟机执行 Java 方法(字节码)服务, 虚拟机栈描述的是 Java 方法执行的内存模型:每个方法被执行的时候都会创建一个栈帧,存储局部变量表、操作栈、动态链接、方法出口。 每一个方法被调用到执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
**本地方法栈(线程私有)**:(Native Method Stacks)为虚拟机使用到的 Native 方法服务。
java 堆(线程共享):虚拟机启动时创建(内存最大),用于存放对象实例。垃圾收集器主要管理的就是 Java 堆。Java 堆在物理上可以不连续,只要逻辑上连续即可。
方法区(线程共享): 存储已被虚拟机加载的类信息、常量、静态
变量、即时编译器编译后的代码等数据,也不需要连续的内存
运行时常量池: 方法去的一部分,保存Class文件的符号引用、翻译出来的直接引用。运行时常量池可以在运行期间将新的常量放入池中。用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
引用计数法: 给对象添加一个引用计数器,每当有一个地方引用它,计数器就+1,;当引用失效时,计数器就-1;任何时刻计数器都为0的对象就是不能再被使用的。缺点在于:很难解决对象之间的循环引用问题。
根搜索算法:通过 “GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到 GC Roots 没有任何引用链相连(用图论的话来说就是从 GC Roots 到这个对象不可达)时,则证明此对象是不可用的。
强引用 Strong Reference: 把一个对象赋给一个引用变量,这个引用变量就是一个强引用。Object obj = new Object();这个就是强引用,垃圾收集永远不会回收被引用的对象。
软引用Soft Reference:还有用,但非必须的对象。在内存溢出前,会被列入回收范围,并进行二次回收。
弱引用 Weak Reference: 只能生存到下一次垃圾收集发生前。
虚引用 Phantom Reference:目的是希望在这个对象被收集器回收时,收到一个系统通知
标记-清除(Mark-Sweep):第一阶段标记所有被引用的对象,第二阶段遍历整个堆,删除未标记对象,需要暂停,会产生内存碎片
复制(Copying)-新生代:划分2块,回收时,将未使用的复制到另一块,空间成本高,在对象存活率较高时,需要执行较多的复制操作,效率会变低。一般用来回收新生代,一般是8:1,1是新生代。
标记-整理(Mark-Compact)-老年代: 同标记,第二阶段把存活对象“压缩”到堆的其中一块,按顺序排放
分代收集算法:把堆分为新生代(用复制算法)和老生代(用标记-清理)
Minor GC (新生代) Full GC (老生代),一般老比新慢10倍以上。
**永久代(Permanent Generation)**: 用于存储被 JVM 加载的类信息、 常量、 静态变量、 即时编译器编译后的代码等数据(java8已经移除,被元数据区取代,元空间并不在虚拟机中,而是使用本地内存)
组成:Class文件是一组以8位字节为基础单位的二进制流,各个数据项目间没有任何分隔符。当遇到8位字节以上空间的数据项时,则会按照高位在前的方式分隔成若干个8位字节进行存储。
魔数: 每个Class文件的头4个字节称为魔数(Magic Number),它的唯一作用是用于确定这个文件是否为一个能被虚拟机接受的Class文件。
版本号:第5,6字节是次版本号,第7,8字节是主版本号。
作用:实现加载动作,用于确定类。任意一个类都需要由类加载器和这个类本身确立其在虚拟机中的唯一性。
双亲委派模型要求除了顶层的启动类加载器外,其余加载器都应当有自己的父类加载器。类加载器之间的父子关系,通过组合关系复用。
工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有到父加载器反馈自己无法完成这个加载请求(它的搜索范围没有找到所需的类)时,子加载器才会尝试自己去加载。
Java类随着它的类加载器一起具备了一种带优先级的层次关系。比如java.lang.Object,它存放在rt.jar中,无论哪个类加载器要加载这个类,最终都是委派给启动类加载器进行加载,因此Object类在程序的各个类加载器环境中,都是同一个类。
如果没有使用双亲委派模型,让各个类加载器自己去加载,那么Java类型体系中最基础的行为也得不到保障,应用程序会变得一片混乱。
关键字volatile是Java虚拟机提供的最轻量级的同步机制(线程不安全),性能优于锁。2个特性:
保证此变量对所有线程的可见性。当一条线程修改了这个变量的值,新值对于其他线程是可以立即得知的。
禁止指令重排序优化。普通变量仅仅能保证在该方法执行过程中,得到正确结果,但是不保证程序代码的执行顺序
在JavaSE1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。
锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率。
自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时 才能进入临界区,避免了线程切换的开心。(让自己循环取值,等其他人完成后改变值才醒来,占cpu,但恢复快)缺点是占用处理器时间。
偏向锁:消除数据在无竞争情况下的同步原语,进一步提高程序的运行性能。即在无竞争的情况下,把整个同步都消除掉。这个锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要同步。
轻量级锁:在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。
公平锁:多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁。
创建阶段 、 应用阶段 、不可见阶段 、不可达阶段 、收集阶段 、终结阶段、 对象空间重新分配阶段 详情
JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。
虚拟机的类加载机制是 :虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。
JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化(后面还有 使用和卸载)。
GC是垃圾回收,java自动检测不在作用域的对象,自动清理内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。GC通过有向图确定对象是否 “可达”,对不可达对象进行回收。可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行
JVM 中堆和栈属于不同的内存区域,使用目的也不同。栈常用于保存方法帧和局部变量,而对象总是在堆上分配。栈通常都比堆小,也不会在多个线程之间共享,而堆被整个 JVM 的所有线程共享。
栈:在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。
堆:堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。
是什么 - 为什么 - 怎么用
什么是分布式 为了解决单个物理服务器容量和性能瓶颈问题而采用的优化手段。 水平扩展,垂直拆分。
什么是线程?线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位
线程和进程有什么区别? 线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。每个线程都拥有单独的栈内存用来存储本地数据。
如何在Java中实现线程 继承java.lang.Thread 类或者直接调用Runnable接口来重写run()方法实现线程,Callable和Future创建线程 util包下。
什么是线程池? 为什么要使用它?
创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。
为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。
从JDK1.5开始,Java API提供了Executor框架让你可以创建不同的线程池。比如单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合很多生存期短的任务的程序的可扩展线程池)。
join方法 把指定的线程加入到当前线程中
主线程启动子线程,如果子线程中要进行大量的耗时运算,主线程会早于子线程结束,这时候主线程如果想等待子线程完成之后再运行,就需要join()方法

继承 Thread 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例。start()方法是一个 native 方法,它将启动一个新线程,并执行 run()方法。
1 | public class MyThread extends Thread { |
实现 Runnable 接口
1 | public class MyThread extends OtherClass implements Runnable { |
ExecutorService、 Callable
有返回值的任务必须实现 Callable 接口,类似的,无返回值的任务必须 Runnable 接口。执行
Callable 任务后,可以获取一个 Future 的对象,在该对象上调用 get 就可以获取到 Callable 任务
返回的 Object 了,再结合线程池接口 ExecutorService 就可以实现传说中有返回结果的多线程了。
1 | //创建一个线程池 |
多线程操作(比如异步通知,或者一些操作的后续处理,为了不影响相应时间),我们是启动的时候new了队列,BlockingQueue LinkedBlockingQueue
进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。
一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
区别
a,地址空间:进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间;
b,资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资
c,线程是处理器调度的基本单位,但进程不是.
d,二者均可并发执行.
在Java中有两类线程:用户线程 (User Thread)、守护线程 (Daemon Thread)。
守护线程和用户线程的区别在于:守护线程依赖于创建它的线程,而用户线程则不依赖。举个简单的例子:如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。

实时系统:FIFO(First Input First Output,先进先出算法),SJF(Shortest Job First,最短作业优先算法),SRTF(Shortest Remaining Time First,最短剩余时间优先算法)。
交互式系统:RR(Round Robin,时间片轮转算法),HPF(Highest Priority First,最高优先级算法),多级队列,最短进程优先,保证调度,彩票调度,公平分享调度。
时间片轮转法
ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候
线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,
如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断
如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情
ReentrantLock获取锁定与三种方式:
a) lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
c)tryLock(long timeout,TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
d) lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断
总体的结论先摆出来:
synchronized:
在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronized,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。
ReentrantLock:
ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。
线程池的作用:
在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:提高线程的可管理性。
常用线程池:ExecutorService 是主要的实现类,其中常用的有
Executors.newSingleThreadPool(),newFixedThreadPool(),newcachedTheadPool(),newScheduledThreadPool()。
线程池的4个组成部分
线程池管理器:用于创建并管理线程池;
工作线程:线程池中的线程;
任务接口:每个任务必须实现的接口,用于工作线程调度其运行;
任务队列:用于存放待处理的任务,提供一种缓冲机制。
1 | public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize, long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue) { |
7个阻塞队列
记:数组有界阻塞队列、支持优先级排序无界阻塞、支持优先级队列无界阻塞、不存数据阻塞、链表(有界、无界、双向)阻塞
按照先进先出(FIFO)原则排序默认情况下不保证访问者公平的访问队列,因为公平访问降低吞吐量。
基于链表的阻塞队列,按照先进先出(FIFO)原则排序,其对于生产者端和消费者端分别采用了独立的锁来控制数据同步,能够处理并发数据。
采取自然顺序升序排列,可自定义实现 compareTo()。
支持延时获取元素的无界阻塞队列。队列使用 PriorityQueue实现
缓存系统的设计:可以用 DelayQueue 保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能从 DelayQueue 中获取元素时,表示缓存有效期到了。
定时任务调度: 使 用 DelayQueue 保 存 当 天 将 会 执 行 的 任 务 和 执 行 时 间 , 一 旦 从DelayQueue 中获取到任务就开始执行,从比如TimerQueue 就是使用 DelayQueue 实现的。
是一个不存储元素的阻塞队列。每一个 put 操作必须等待一个 take 操作,否则不能继续添加元素。(传递器)
多了 tryTransfer(试探下有没传入数据,没有就返回false,有没有数据都立即返回结果)、transfer 方法(去取数据,没数据就等,直到有数据才返回)
双向队列指的你可以从队列的两端插入和移出元素。
添加元素
Java中的阻塞队列接口BlockingQueue继承自Queue接口。BlockingQueue接口提供了3个添加元素方法。
add:添加元素到队列里,添加成功返回true,由于容量满了添加失败会抛出IllegalStateException异常
offer:添加元素到队列里,添加成功返回true,添加失败返回false
put:添加元素到队列里,如果容量满了会阻塞直到容量不满
删除方法
3个删除方法
poll:删除队列头部元素,如果队列为空,返回null。否则返回元素。
remove:基于对象找到对应的元素,并删除。删除成功返回true,否则返回false
take:删除队列头部元素,如果队列为空,一直阻塞到队列有元素并删除
队列中每个元素都有个过期时间,并且队列是个优先级队列,当从队列获取元素时候,只有过期元素才会出队列。
在java.util.concurrent.atomic包下,可以分为四种类型的原子更新类:原子更新基本类型、原子更新数组类型、原子更新引用和原子更新属性。
原子更新基本类型
使用原子方式更新基本类型,共包括3个类:
AtomicBoolean:原子更新布尔变量
AtomicInteger:原子更新整型变量
AtomicLong:原子更新长整型变量
原子更新数组
通过原子更新数组里的某个元素,共有3个类:
AtomicIntegerArray:原子更新整型数组的某个元素
AtomicLongArray:原子更新长整型数组的某个元素
AtomicReferenceArray:原子更新引用类型数组的某个元素
AtomicIntegerArray常用的方法有:
int addAndSet(int i, int delta):以原子方式将输入值与数组中索引为i的元素相加
boolean compareAndSet(int i, int expect, int update):如果当前值等于预期值,则以原子方式更新数组中索引为i的值为update值
原子更新引用类型
AtomicReference:原子更新引用类型
AtomicReferenceFieldUpdater:原子更新引用类型里的字段
AtomicMarkableReference:原子更新带有标记位的引用类型。
原子更新字段类
如果需要原子更新某个类的某个字段,就需要用到原子更新字段类,可以使用以下几个类:
AtomicIntegerFieldUpdater:原子更新整型字段
AtomicLongFieldUpdater:原子更新长整型字段
AtomicStampedReference:原子更新带有版本号的引用类型。
要想原子更新字段,需要两个步骤:
每次必须使用newUpdater创建一个更新器,并且需要设置想要更新的类的字段
更新类的字段(属性)必须为public volatile
死锁产生的四个必要条件
互斥条件:资源是独占的且排他使用,进程互斥使用资源,即任意时刻一个资源只能给一个进程使用,其他进程若申请一个资源,而该资源被另一进程占有时,则申请者等待直到资源被占有者释放。
不可剥夺条件:进程所获得的资源在未使用完毕之前,不被其他进程强行剥夺,而只能由获得该资源的进程资源释放。
请求和保持条件:进程每次申请它所需要的一部分资源,在申请新的资源的同时,继续占用已分配到的资源。
循环等待条件:在发生死锁时必然存在一个进程等待队列{P1,P2,…,Pn},其中P1等待P2占有的资源,P2等待P3占有的资源,…,Pn等待P1占有的资源,形成一个进程等待环路,环路中每一个进程所占有的资源同时被另一个申请,也就是前一个进程占有后一个进程所深情地资源。
解决死锁
一是死锁预防,就是不让上面的四个条件同时成立。
二是,合理分配资源。
三是使用银行家算法,如果该进程请求的资源操作系统剩余量可以满足,那么就分配。
1.开放地址法 2.再哈希法 3.链地址法(hashmap) 4.建公共溢出区
juc - 详细名称 concurrent 用过那个,知道为什么这么用 LinkedBlockingQueue (几个子类的区别) 需要记得有哪些子类 - 各有什么区别 。
hreadLocal为每个线程维护一个本地变量。
采用空间换时间,它用于线程间的数据隔离,为每一个使用该变量的线程提供一个副本,每个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突。
ThreadLocal类中维护一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值为对应线程的变量副本。
4个方法:get/set/remove/ initialValue
可以用于解决SimpleDateFormat的线程安全
1 | public class SimpleDateFormatDemo { |
ThreadLocalMap内部是利用Entry来进行key-value的存储的。
1 | static class Entry extends WeakReference<ThreadLocal> { |
上面源码中key就是ThreadLocal,value就是值,Entry继承WeakReference,所以Entry对应key的引用(ThreadLocal实例)是一个弱引用。
1 | /** |
这个set操作和集合Map解决散列冲突的方法不同,集合Map采用的是链地址法,这里采用的是开放定址法(线性探测)。set()方法中的replaceStaleEntry()和cleanSomeSlots(),这两个方法可以清除掉key ==null的实例,防止内存泄漏。
1 | private Entry getEntry(ThreadLocal key) { |
由于采用了开放定址法,当前key的散列值和元素在数组中的索引并不是一一对应的,首先取一个猜测数(key的散列值),如果所对应的key是我们要找的元素,那么直接返回,否则调用getEntryAfterMiss
1 | private Entry getEntryAfterMiss(ThreadLocal key, int i, Entry e) { |
这里一直在探测寻找下一个元素,知道找的元素的key是我们要找的。这里当key==null时,调用expungeStaleEntry有利于GC的回收,用于防止内存泄漏。
ThreadLocalMap的key为ThreadLocal实例,他是一个弱引用,我们知道弱引用有利于GC的回收,当key == null时,GC就会回收这部分空间,但value不一定能被回收,因为他和Current Thread之间还存在一个强引用的关系。由于这个强引用的关系,会导致value无法回收,如果线程对象不消除这个强引用的关系,就可能会出现OOM。有些时候,我们调用ThreadLocalMap的remove()方法进行显式处理。
ThreadLocal不是用来解决共享变量的问题,也不是协调线程同步,他是为了方便各线程管理自己的状态而引用的一个机制。
每个ThreadLocal内部都有一个ThreadLocalMap,他保存的key是ThreadLocal的实例,他的值是当前线程的局部变量的副本的值。
一个提供原子操作的 Integer 的类,同理的还有几个都在atomic包下。在多线程程序中,诸如++i 或 i++等运算不具有原子性,是不安全的线程操作之一。通常我们会使用 synchronized 将该操作变成一个原子操作,但 JVM 为此类操作特意提供了一些同步类,使得使用更方便,且使程序运行效率变得更高。
锁-单机锁如何实现 - sys 的好像就是同步和互斥锁.
同步锁和互斥锁的区别 同步就是一起用,互斥就是谁拿到了就是谁的,其他人睡着.
锁的状态总共有四种:无锁状态、偏向锁、轻量级锁和重量级锁。 锁可以升级,但不可降级。
偏向锁:目的是在某个线程获得锁之后,消除这个线程锁重入(CAS)的开销,看起来让这个线程得到了偏护
阻塞锁:让线程到阻塞状态等待,得到通知醒来开始竞争.不占cpu资源,但是恢复慢.竞争激烈使用阻塞锁,不激烈使用自旋锁.
悲观锁 - 假设最差情况- 每次拿别人都在改- 所以每次拿数据都上锁,比如行锁,表锁,读锁,写锁.等 synchronized和ReentrantLock等独占锁就是悲观锁思想的实现
乐观锁(CAS)假设都是最好情况,别人不会改,所以不上锁,就判断这期间有没有人改数据,所以通过version判定,适用于多读情况 . 可以提高吞吐量.
乐观锁适用于写比较少的情况下(多读场景)但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。
**乐观锁实现 : **1 version. 2 CAS算法 - 比较需要读写的值.与原先相同就修改,不同就不操作.一般情况下是自旋操作,即不断重试.
共享锁与独占锁:共享锁是一种乐观锁 ,独占锁是一种悲观锁
可重入锁指的是在同一个线程中外层函数获取锁后,内层函数仍然有获取该锁的代码,却不受影响。在java中,ReentrantLock与 synchronized 都是可重入锁。(避免死锁)
https://blog.csdn.net/qq_36299025/article/details/89883989
公平锁(Fair):加锁前检查是否有排队等待的线程,优先排队等待的线程,先来先得
非公平锁(Nonfair):加锁时不考虑排队等待问题,直接尝试获取锁,获取不到自动到队尾等待。
非公平锁性能比公平锁高 5~10 倍,因为公平锁需要在多核的情况下维护一个队列;Java 中的 synchronized 是非公平锁, ReentrantLock 默认的 lock()方法采用的是非公平锁。
如果一个锁守护多个相互独立的状态变量,你可能能够通过拆分锁,使每个锁守护不同的变量,从而改进伸缩性.这样可以使锁的请求频率都变小.分拆锁对于中等竞争强度锁,能够转化为非竞争锁. 分拆锁的扩展,分为若干加锁块集合,并且他们属于相互独立对象,这个情况就是分离锁.如:ConcurrentHashMap就实现了16个锁数组,各自守护1/16. - (原文在深入分布式缓存中)
1)多个读者可以同时进行读
2)写者必须互斥(只允许一个写者写,也不能读者、写者同时进行)
3)写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)
Java中读写锁有个接口java.util.concurrent.locks.ReadWriteLock也有具体的实现ReentrantReadWriteLock。
**减少锁持有时间 **:只用在有线程安全要求的程序上加锁
减小锁粒度:将大对象拆分为小对象,降低锁竞争,可以提升偏向锁、轻量锁的成功率。典型案例还是ConcurrentHashMap
锁分离:读写锁就是锁分离。 LinkedBlockingQueue 从头部取出,从尾部放数据。
锁粗化:在某些情况下,不停的请求、同步、释放,本身会消耗系统资源,不利于性能优化(与减小粒度相反)。
锁消除:编译器层面优化。详情
使用双锁分离就得注意一点,那就是防止线程夯死。生产线程要唤醒生产线程,消费线程也要唤醒生产线程,消费线程唤醒消费线程,消费线程也要唤醒生产线程。
1、数据库实现(效率低,不推荐)
2、redis实现(使用redission实现,但是需要考虑思索,释放问题。繁琐一些)
3、Zookeeper实现 (使用临时节点,效率高,失效时间可以控制)
4、Spring Cloud 实现全局锁(内置的)
https://www.cnblogs.com/wangjintao-0623/p/9727272.html
synchronized 同步代码块时,一个时间内只能有一个线程得到执行.其他线程需要等待(加法计数器用到 - 计数器+机器码 生成订单号)
同步锁(lock)
1 | //Lock是控制多个线程对共享资源进行访问的工具.通常,锁提供了对共享资源的独占访问,每次只能有一个,线程对Lock对象加锁,线程开始访问共享资源之前,应该先获得Lock对象。 |
多线程情况下,一个消费者线程,一个生产者线程。
生产者
1 | count+1; |
消费者
1 | while(count<=0) |
如果两个步骤同时执行

如何解决 - 通过同步的方式:只能有一个执行,就可以解决这个问题。(java有强制要求)
面向切面编程,使用”横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与业务逻辑关系不大的部分是横切关注点。横切关注点经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事务管理等。
AOP基于代理模式,动态代理 :AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成aop对象.aop对象包含目标的全部方法,并在特定切点进行增强处理,然后回调原对象.
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理
JDK动态代理是基于Java的反射机制实现的,主要涉及到java.lang.reflect包中的Proxy和InvocationHandler。
InvocationHandler是一个接口,通过实现这个接口定义一个横切的逻辑!然后通过反射机制调用目标类的方法,这样就能动态的把非业务逻辑和业务逻辑动态的拼接在一起.
proxy则利用InvocationHandler创建代理实例,来间接的调用代理的方法!
JDK的反射是基于接口的!也就是你的service一定是有接口的不然是不行的!这时候就有个Cglib可以顶上了!
Cglib采用了底层的字节码技术,为代理类创建了一个子类来代理它!
1 |
|
插入日志功能
1 |
|
spring优点:低侵入,IOC低耦合,AOP对日志安全等通用应用统一管理,高复用.
IOC是什么,控制反转,让对象创建不用去new.由spring通过反射机制根据配置文件在运行时动态创建对象.spring提供4种集合配置,如:list,set,map,props(双string的map)
Spring 事务传播
required:没有就创建,存在就加入
supports:存在就加入,不存在就不做事务
mandatory:存在就加入,不存在就抛异常
requires_new:不管是否存在都新建
no_supported:如果存在事务将事务挂起.
nerver:存在事务我就抛异常.
nested:存在就嵌套,不存在就创建
事务隔离级别:
default:默认db级别
read_uncommitted:读取未提交(会脏读),基本不用
read_committed:读取已提交(会幻读,不可重复读)
repeatable_read:可重复读,行锁(会幻读)
serializable:完全看不到其他事务的操作,表锁
解释Spring支持的几种bean的作用域。
1 | Spring框架支持以下五种bean的作用域: |
Spring是实现了工厂模式的工厂类。这个类名为BeanFactory(实际上是一个接口),在程序中通常BeanFactory的子类ApplicationContext。Spring相当于一个大的工厂类,在其配置文件中通过
IOC,IOC就是一个容器,负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。很好地实现模块之间的解耦,@Autowired,不用每次去new service。
AOP面向切面,如:系统中有很多各不相干的类的方法,在这些众多方法中要加入某种系统功能的代码(是否能理解是类似于中间件),例如,加入日志,加入权限判断,加入异常处理,Transactions事务,Synchronization同步
实现AOP功能采用的是代理技术,客户端程序不再调用目标,而调用代理类,代理类与目标类对外具有相同的方法声明,有两种方式可以实现相同的方法声明,一是实现相同的接口,二是作为目标的子类。
容器:Spring 包含并管理应用中对象的生命周期和配置。
MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。
ApplicationContext通常的实现是什么?
FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。
ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。
WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。
Spring beans 是那些形成Spring应用的主干的java对象。它们被Spring IOC容器初始化,装配,和管理。这些beans通过容器中配置的元数据创建。比如,以XML文件中
Spring 框架定义的beans都是单件beans。在bean tag中有个属性”singleton”,如果它被赋为TRUE,bean 就是单件,否则就是一个 prototype bean。默认是TRUE,所以所有在Spring框架中的beans 缺省都是单件。
Spring容器从XML 文件中读取bean的定义,并实例化bean
Spring根据bean的定义填充所有的属性
如果bean实现了BeanNameAware 接口,Spring 传递bean 的ID 到 setBeanName方法;
如果Bean 实现了 BeanFactoryAware 接口, Spring传递beanfactory 给setBeanFactory 方法。
如果有任何与bean相关联的BeanPostProcessors,Spring会在postProcesserBeforeInitialization()方法内调用它们。
如果bean实现IntializingBean了,调用它的afterPropertySet方法,如果bean声明了初始化方法,调用此初始化方法。
如果有BeanPostProcessors 和bean 关联,这些bean的postProcessAfterInitialization() 方法将被调用。
如果bean实现了 DisposableBean,它将调用destroy()方法。
Spring MVC的核心就是 DispatcherServlet , 一个请求经过 DispatcherServlet ,转发给HandlerMapping ,然后经反射,对应 Controller及其里面方法的@RequestMapping地址,最后经ModelAndView和ViewResoler返回给对应视图 。

1 | //测试拦截器1 |
- preHandle方法:进入Handler方法之前执行。可以用于身份认证、身份授权。比如如果认证没有通过表示用户没有登陆,需要此方法拦截不再往下执行(return false),否则就放行(return true)。
- postHandle方法:进入Handler方法之后,返回ModelAndView之前执行。可以看到该方法中有个modelAndView的形参。应用场景:从modelAndView出发:将公用的模型数据(比如菜单导航之类的)在这里传到视图,也可以在这里同一指定视图。
- afterCompletion方法:执行Handler完成之后执行。应用场景:统一异常处理,统一日志处理等。
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
(1)BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
①继承MessageSource,因此支持国际化。
②统一的资源文件访问方式。
③提供在监听器中注册bean的事件。
④同时加载多个配置文件。
⑤载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
①BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
②ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。
③相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。
(3)BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。
(4)BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,<context:annotation-config />。在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
如果查询的结果不止一个,那么@Autowired会根据名称来查找;
如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。
@Autowired可用于:构造函数、成员变量、Setter方法
注:@Autowired和@Resource之间的区别
(1) @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
(2) @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。
生产遇到一个异常情况,报运行时异常,缺还是修改了数据库数据。
本地测试发现,在保存后,直接抛异常,并没有回滚数据。
用debug查看,发现已经打印了回滚日志了,但是数据库没生效。
由于我们是多数据源情况,感觉是spring的事务是否启动了,
1 | <tx:annotation-driven transaction-manager="transactionManagerWallet"/> |
xml中加入了,这个,发现,可以。但是,另外的数据源就出问题了。
经过测试发现,在类上面加了@Transactional(transactionManager = “transactionManagerWallet”)
然后,方法上又加了@Transactional可能会导致 类上的 事务,被覆盖掉,导致,调到了其他的事务中
后续方法上所有的@Transactional 都需要带对应的transactionManager,或者就不要写,如果类上有的话。这样就不会存在被覆盖的问题。
1 | (parameters) -> expression |
echo “” > catalina.out
1 | 查询启动 |
touch 如果不存在文件,则创建文件
mkdir –help 查看简单命令描述
man mkdir 查看命令详细描述
cat 文件名 (全部显示)
more 文件名 (分屏显示, 空格后 继续显示)
grep 查询文件是否包含指定内容
使用:grep [-n 对于行号 -v 显示不包含 -i 忽略大小写] 内容 文件名称
同时可以用正则查找 : ^xx xx开头 。 dd$ dd结尾
1 | > 输出 |
1 | 将 一个命令的输出 可以通过管道 做为 另一个命令的输入 |
如果名字前带.说明是 隐藏文件 ,如.sh 如何查看? ls -alh
1 | ssh-keygen 生成ssh 密钥 全回车即可 |
1 | 在 ~/.ssh/config 中 加入 |
1 | scp 文件 root@xx.xx.xx.xx:地址 将文件复制到 地址 中 |
1 | -rw-r--r-- 1 unicersexin staff 56 2 23 09:51 config |
df(disk free 显示磁盘剩余空间) du -h 目录名 -h 人性化显示
ps(process status 查看进程详情) top(动态显示并排序) kill -9(干掉它)
1 | ps aux(a显示终端所有进出 u显示进程详细状态 x 显示没有控制终端的进程) |
不输入路径 表示在当前文件夹下
find [路径] -name “条件 如果 *.py 或者 wxy”
在linux 中 文件名和文件的数据 是分开存储的.
软连接文件名->软链接数据->文件名->文件数据
软链接文件数据 关联 文件名
硬链接 : ln 不带 -s 会创建硬链接, 文件名与硬链接 都关联文件数据
tar linux 最常用的备份工具.
打包: tar -cvf 打包文件.tar 被打包文件或者路径…(依次添加,接下去)
解包: tar -xvf 捷豹文件.tar
tar -zcvf 压缩文件.tar.gz
tar -zxcf 解压文件.tar.gz (-C 目标路径。解压到某个路径下)
tar -jcvf 压缩文件.tar.bz2
tar -jxvf 解压文件.tar.bz2
sudo apt install 软件包 安装
sudo apt remove 软件名 删
sudo apt upgrade 升级
total 总内存 used 已使用 free可用
文件夹:mkdir 文件:touch
unzip(需要安装) tar xf(-zxvf) xx.tar.gz
chmod [对象] +/-[权限] [文件] 例如: chmod u+x ./xxx.sh u所有者 加入x执行操作
创建 useradd wxyadmin
删除 userdel wxyadmin
密码 passwd wxyadmin
vi /etc/sysconfig/iptables
重启配置 service iptables restart
1 | 打印 :echo "请输入1" |
挂载: sudo mount /dev/sdb1 /mnt/
卸载 : sudo umount /mnt/
1 | !/bin/sh //脚本解析器路径 |
查询 netstat -anp 所有开放端口信息
关闭端口号:
1 | iptables -A OUTPUT -p tcp --dport 端口号-j DROP |
打开端口号:
1 | iptables -A INPUT -ptcp --dport 8099 -j ACCEPT |
如果无法使用iptable操作
1 | service iptables save出错please try to use systemctl. |