首页 文章 精选 留言 我的

精选列表

搜索[基础搭建],共10000篇文章
优秀的个人博客,低调大师

Go基础(复杂类型):函数的闭包

函数的闭包 Go 函数可以是一个闭包。闭包是一个函数值,它引用了其函数体之外的变量。该函数可以访问并赋予其引用的变量的值,换句话说,该函数被“绑定”在了这些变量上。 例如,函数 adder 返回一个闭包。每个闭包都被绑定在其各自的 sum 变量上。 一、下面来看一个例子咯: package main import "fmt" func adder() func(int) int { sum := 0 return func(x int) int { sum += x return sum } } func main() { pos, neg := adder(), adder() for i := 0; i < 10; i++ { fmt.Println( pos(i), neg(-2*i), ) } } 输出的结果: 0 0 1 -2 3 -6 6 -12 10 -20 15 -30 21 -42 28 -56 36 -72 45 -90

优秀的个人博客,低调大师

C++程序设计基础(6)内存分配

1.知识点 三步走:申请,释放,指针置空。 1.1malloc、free函数 在C语言中内存malloc函数申请动态空间,以下展示其基本用法: 1 int *p = NULL; 2 p = (int *)malloc(sizeof(int) * 10);//申请 3 free(p);//释放,否则会造成内存泄漏 4 p = NULL;//指针置空,否则成为野指针 (1)动态分配的空间来自队空间,而指针本身作为局部变量存储在栈空间中。 (2)malloc有时候也可能申请空间失败,这时返回NULL,故需要对其进行判断。 (3)通过malloc动态申请的空间必须通过free函数释放,这两个函数成对出现。否则可用空间会越来越少。 (4)在通过free函数释放之后,最好将指针置空。 (5)malloc/free函数申请释放的过程其实就是可用空间链表不断在更新。 1.2new、delete函数 (1)new和delete运算符既可以应用于基本类型,也可以用于自定义类型,new操作符不仅申请了空间,然后还根据提供的参数进行构造函数初始化,delete在释放内存空间之前还会调用对象的析构函数,这些事new/delete比malloc/free更为丰富的地方。 2.面试题 2.1malloc和free的常识性问题 以下说法正确的是(D)。 (A)free会将指针置为空 //需要手动置空 (B)malloc函数的返回指针移动后,free函数会自动找到首地址并释放 //不能失去对首地址的控制,否则无法释放 (C)malloc函数一次申请N个int空间,使用后需要循环N次逐一调用free释放 //malloc和free成对出现 (D)malloc申请的空间位于堆上 2.2返回一个64整数倍的地址 编写两个函数,align64malloc和align64free,分别用于申请空间和释放空间,并要求申请空间返回的地址必须是64的整数倍。 解析:在所需空间前面再加上64个字节,可保证其中肯定有一个地址是64的倍数,再在这64个字节空间的前面再加上4个字节保证有地方可以存储返回的首地址。如下表所示 A 4个字节 B 64个 字节 C N个字节 1 void * align64malloc(int size) { 2 void *ptr = malloc(sizeof(int)*size + 64 + sizeof(void *)); 3 if (!ptr) { 4 return NULL; 5 } 6 ptr = (char *)(ptr)+sizeof(void *); //在最前面预留出来了存放首地址的存储空间 7 //接下来一步需要将首地址空间放入到64整数倍前面的空间中去 8 *((int *)(((int)ptr+64-(int)ptr%64)-sizeof(void *)))=(int)ptr - sizeof(void *);//等式右边为首地址,void*是不可以进行加减运算 9 return (void *)((int)ptr + 64 - (int)ptr % 64); 10 } 11 12 void algin64free(void * ptr) { 13 if (ptr) { 14 free((void *)(*((void **)ptr - 1)));//void *不能进行加减,转换成指针的指针之后可以进行加减 15 } 16 } 2.3简述malloc/free和new/delete的区别 (1)malloc/free是C语言提供的库函数,通过函数调用访问,需要传递参数并接收返回值;而new/delete是C++提供的操作符,有自己的一套语法规则和运算方式。 (2)malloc/free只能用于基本的数据类型,而new/delete不但能用于基本数据类型,还可以用于面向对象中的自定义类型。 (3)malloc函数返回的是void*类型,程序需要显示的转换成所需要的指针类型,new操作符后面直接指明了类型,不涉及类型转换问题。 (4)malloc只负责申请空间,并返回首地址;new运算符除了申请空间,还会调用构造函数初始化指针指向的内容;free韩式只负责 释放空间,并标识这段空间为可用空间;delete运算符除了释放空间,还会调用对象的析构函数。 (5)事实上,后者覆盖了前者的全部功能,之所以在C++中还保留malloc/free函数,主要是为了解决兼容性问题,防止C++中调用包含malloc/free的C函数时出现错误。 2.4简述delete和delete[]的区别 答案(1)当new[]中数组的元素是基本类型时,通过delete和delete[]都可以释放数组空间; (2)当new[]中的数组元素是自定义的类型时,只能通过delete[]释放数组空间(因为用delete只调用第一个元素的析构函数)。 强烈建议申请和释放空间是采用完全配对的方式:new和delete成对使用,new[]和delete[]成对使用。 以下两个例子说明: 1 //基本类型时二者都可以 2 //A 3 int *i = new int[5]; 4 delete i; 5 //B 6 int *i = new int[5]; 7 delete[] i; 1 //自定义类型new[]/delete[]必须成对 2 class Test { 3 private: 4 char *text; 5 public: 6 Test(int lenght = 100) { 7 text = new char[lenght]; 8 } 9 ~Test() { 10 delete text; 11 cout << "A destructor" << endl; 12 } 13 }; 14 15 Test *a = new Test[5]; 16 delete[] a;//使用delete会出错

优秀的个人博客,低调大师

C++程序设计基础(7)位运算

注:读《程序员面试笔记》笔记总结 1.知识点 运算 符号 说明 与 & 有0为0,都1为1 或 | 由1为1,都0为0 非(取反) ~ 0变1,1变0 异或 ^ 同为0,异为1 左移 << 高位移除,低位补零 右移 >> 低位移除,高位补0 1.1异或的性质 1 a^a==0 2 0^a==a 3 a^b^b==b^a^b==a 2.面试题 2.1不使用变量交换两个值 1 //method one 2 a = a - b;//save b message 3 b = a + b;//b= old a 4 a = b - a; 5 //method two 6 a = a ^ b; 7 b = a ^ b;//b= old a 8 a = a ^ b; 提示:利用位的运算性质 2.2计算二进制的1的个数 1 //method one 2 for ( count = 0; num != 0; num=num >> 1) { 3 if (num & 1) { 4 count++; 5 } 6 } 7 //method two 8 for ( count = 0; num != 0; num &= num - 1) {//每次消掉最后的一个1 9 count++; 10 } 提示:一个数与自身减一后与操作,会消除末尾的1,每次消除一个1 2.3将二进制数倒数第M位的前N位取反(比如M=2,N=4) (1)将1左移N位(00000001=>00010000); (2)将步骤一得到的数减1(00010000=>00001111); (3)将步骤二得到的数左移M位(00001111=>00111100); (4)得到的数字与原数字进行异或。 1 int getNum(int num, int n, int m) { 2 int res = 1 << n; 3 res--; 4 res = res << m; 5 return res ^ num; 6 } 2.4找出人群中的唯一单身狗(一个数组中唯一一个数出现一次,其余的数都出现过偶数次,求该数) 1 int getSingleDog(int *a, int n) { 2 int res = 0; 3 for (int i = 0; i < n; i++) { 4 res ^= a[i]; 5 } 6 return res; 7 } 提示:异或的性质b^b==0以及交换律 2.5(找出人群中三个单身狗中的任意一个) 1 #define BITNUM 32 2 int getSingelNum_OneOfThree(int *a, int len) { 3 for (int i = 0; i < BITNUM; i++) { 4 int countOdd = 0, countEven = 0; 5 int resOdd = 0, resEven = 0; 6 int tem = 1 << i; 7 8 for (int j = 0; j < len; j++) { 9 if (tem & a[j]) { 10 countOdd++; 11 resOdd ^= a[j]; 12 } 13 else { 14 countEven++; 15 resEven ^= a[j]; 16 } 17 } 18 19 if (countOdd & 1 && resEven)//一组个数为奇数,另一组异或值不为零 20 return resOdd; 21 if (countEven & 1 && resOdd)//一组个数为奇数,另一组异或值不为零 22 return resEven; 23 } 24 return -1; 25 } 提示:按位从尾部根据0和1分成两组,当两组都有数,且偶数个的组所有值取异或不为零时,另一组取异或的值极为其中一个满足的值。

优秀的个人博客,低调大师

C++程序设计基础(8)main函数

注:读《程序员面试笔记》笔记总结 1.知识点 (2)main函数的形式 1 //first type 2 int main() 3 //second type 4 int main(int argc,char *argv[]) 不推荐使用void格式,以上两种方式函数以return 0结束; argc(argument count):代表参数的个数; argv(argument value):代表命令行输入的参数,其中argv[0]是程序名; 2.面试题 2.1键鼠main函数执行前后发生了什么 答案:main函数第一行代码执行之前会调用全局对象和静态对象的构造函数,初始化全局变量和静态变量;main函数 最后一行代码执行之后会调用atexit中注册的函数,并且调用顺序与注册顺序相反。

优秀的个人博客,低调大师

Java基础巩固-了解Java中的反射机制

最近有空的时候会看下jdk和spring的源码,发现反射的使用是非常频繁的。之前也对反射或多或少有过了解,但也只是停留在了解的阶段,总结一下来加深自己的印象。 反射的基本概念:程序可以访问、检测和修改其本身状态或行为的一种能力。 反射机制是java的特性之一,指的是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。(摘自百度) 反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取它所有的成员变量和方法并且显示出来(官方概念) 常见应用场景 1.各种框架中,比如spring的IOC(控制反转) spring ioc的思想是将设计好的对象交给容器控制,帮我们实例化,其中就有用到反射来实现。 大致步骤(伪代码) ①spring配置好bean <bean id="courseDao" class="com.qcjy.learning.Dao.impl.CourseDaoImpl"></bean> ②解析bean中class属性 ③通过反射获取Class对象 Class<?> cls = Class.forName(classStr); ④实例化对象 Object obj = cls.newInstance(); ⑤放到容器中 2.tomcat读取web.xml tomcat服务器提供了处理请求和应答的方式,针对不同处理动作,对外提供接口让开发者做相应的具体实现。 参考这里 学习反射机制前,需要先简单了解一下JVM,java之所以能跨平台,是因为java虚拟机。类的加载和运行都是依托它。 jvm内存区域 举个栗子: Object object = new Object(); 运行该程序顺序 1.JVM启动,先将代码编译成.class文件,根据类加载器(Object类由顶层父类Boostrap ClassLoader)加载这个class文件并加载到jvm内存中 2.方法区存类的信息,类加载器通过方法区上类的信息在堆上创建类的Class对象(不是new出来的对象,而是类的类型对象,每个类只有一个Class对象,该Class对象由jvm保证唯一,之后类的创建根据这个Class对象操作)。 3.jvm创建对象前,会先检查类是否被加载,如果加载好,则为对象分配内存,初始化就是代码:new Object() 这种new出对象的方式在实际应用中很常见,相当于程序相当于写死了给jvm去跑。假如一个服务器上突然遇到某个请求要用到某个类,但没加载进jvm,这种时候总不能停下来再new一个这个类的对象,之后再重启服务器。。 这个时候回到java反射的概念。简单来说能动态获取一个类的信息并且去操作它(属性,方法等等…)。它允许在程序在运行时加载,探知使用编译期间已知或未知的class,method,属性,参数等等。 动态加载和静态加载 动态加载:程序在运行期间调用方法,即使方法是错误的程序依旧执行,通过动态加载可以使程序更加灵活方便日后维护 静态加载:程序在编译时执行,在此过程中只要方法出错,编译器会报错,就会中断程序,这是我们常用的。 而反射恰好在编译时不执行,而是在运行期间生效。 jdk中反射中常用的类 java.lang.Class java.lang.reflect.Constructor java.lang.reflect.Field java.lang.reflect.Method java.lang.reflect.Modifier 反射可以做的事 package reflect; //Person类用于后续测试 public class Person { private String sex; public String age; public String work; public String name; public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public String getWork() { return work; } public void setWork(String work) { this.work = work; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Person() { System.out.println("公有,调用无参的构造方法"); } public Person(String name, String sex) { System.out.println("公有,调用有参构造方法" + "name=" + name + "sex" + sex); } private Person(String sex) { System.out.println("调用私有,sex=" + sex); } public void sayHello(String word) { System.out.println("公有方法说的话->" + word); } private void say(String word) { System.out.println("私有方法说的话->" + word); } } 1.获取Class对象(使用Person类做演示) /** * 获取Class对象的三种方式 */ public class ClassTest { public static void main(String[] args) throws ClassNotFoundException { /** * 1. 通过getClass * Object类和Class类都有getClass()本地方法用于获取 * 在Java中所有的类都继承于Object类,但不用在声明一个类时显示的extends Object * 这边采用的是Object类里的getClass()方法 */ Object o = ""; System.out.println("o->" + o.getClass()); //o->class java.lang.String Person p = new Person(); Class clazz1 = p.getClass(); //两个Person对象不同 但类是相同的 就好比说两个人有各个方面不同 但都是人这个类 Person p1 = new Person(); System.out.println("p->" + clazz1);//class reflect.Persons System.out.println(p == p1); //false System.out.println(p.getClass() == Person.class); //true System.out.println(p.getClass() == p1.getClass()); //true /** * 2.类名.class */ Class clazz2 = Person.class;//class reflect.Person /** * 3.Class.forName() jdbc也是通过这种方式加载驱动类 */ Class clazz3 = Class.forName("reflect.Person"); /** * 总结: * 三种获取Class对象方法 1.Object类的getClass() 2.类名.class 3.Class.forName() * 判断实例对象类型 getClass与instance的区别在于getClass不考虑继承 intance的话如果是父类也属于 * 在运行期间,一个类只有一个Class对象产生 Class是单例的 验证如下 * 相比之下 1已经有对象了还要反射显得没啥意义 2要导入类 依赖强 3第三种实用性更强 */ //true意味着三个类对象是同一个类(Class)的实例 System.out.println("class对象是否相等->" + (clazz1 == clazz2 && clazz1 == clazz3));//class对象是否相等->true System.out.println(p.getClass() == o.getClass());//false System.out.println(p instanceof Person && p instanceof Object); //true } } 2.创建对象 这边提一下java创建对象的5种方式 1.使用new 2.使用java.lang.Class类的newInstance() 3.使用Constructor类的newInstance方法 4.使用clone方法 写法类似 Person person = Person.class.newInstance(); Person personClone = (Person)person.clone(); 这边被克隆的类要实现Cloneable并重写clone方法 虽然Cloneable接口为空但也要实现作为标志,否则object的clone方法将报CloneNotSupportedException的错 5.使用反序列化 序列化后对象反序列化 6.动态代理Proxy方式 Proxy的静态方法newProxyInstance 这边2,3,6是使用反射的机制来创建对象。 样例代码 public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { /** * 利用反射机制中的newInstance方法创建对象 */ Class clazz = Class.forName("reflect.Person"); //先获取要创建对象的类的Class对象 Object o = clazz.newInstance(); System.out.println(o.getClass());//class reflect.Person /** * 通过Constructor类创建 * 通过getConstructors方法获得构造器Constructor对象并创建 */ Object o1 = clazz.getConstructor().newInstance(); System.out.println(o1.getClass());//class reflect.Person //可通过创建string对象 Object o2 = String.class.getConstructor(String.class).newInstance("hello world");//class reflect.Person System.out.println(o2);//hello world } 3.获取成员变量并调用 public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class personClass = Class.forName("reflect.Person"); //获取共有字段 如果是private修饰会报NoSuchFieldException Field f = personClass.getField("name"); System.out.println(f); //public java.lang.String reflect.Person.name Field[] af = personClass.getFields(); System.out.println(af);//对象数组 可通过遍历获取 System.out.println(Arrays.stream(af).count()); //公有数目为3 //公有私有都能获取 Field f1 = personClass.getDeclaredField("sex");//private java.lang.String reflect.Person.sex System.out.println(f1); //获取公有字段并调用 Object object = personClass.getConstructor().newInstance(); f.set(object, "garwer"); Person person = (Person)object; System.out.println((person.name));//garwer //获取私有字段并调用 强制变性 - - Person nan = (Person) personClass.newInstance(); nan.setSex("女"); f1.setAccessible(true);//暴力反射 解除私有限定 如果不加上这句会报错 f1.set(nan,"男"); System.out.println(nan.getSex()); //输出男 } 4.获取方法(包含构造方法和成员方法)并调用 package reflect; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TestMethod { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //获取Class对象 Class personClass = Class.forName("reflect.Person"); /** * (一)构造方法 名字定义与类名相同 无返回类型业务void 在创建一个对象使用new操作执行的 主要用于初始化 * 不能被static、final、synchronized、abstract和native等修饰 构造方法不能被子类继承 */ System.out.println("=获取所有公有构造方法="); Constructor[] conArray = personClass.getConstructors(); for(Constructor c : conArray){ System.out.println(c); } System.out.println("=获取所有构造方法(含私有)="); conArray = personClass.getDeclaredConstructors(); for(Constructor c : conArray){ System.out.println(c); } /** * 打印结果 * =获取所有公有构造方法= public reflect.Person(java.lang.String,java.lang.String) public reflect.Person() =获取所有构造方法(含私有)= public reflect.Person(java.lang.String,java.lang.String) private reflect.Person(java.lang.String) public reflect.Person() */ /** * (二)成员方法 */ //获取所有公有方法 System.out.println("=获取所有公有方法="); personClass.getMethods(); Method[] methodArray = personClass.getMethods(); for(Method m : methodArray){ System.out.println(m); } System.out.println("=获取所有方法 包括私有="); methodArray = personClass.getDeclaredMethods(); for(Method m : methodArray){ System.out.println(m); } System.out.println("=获取公有的Person()方法="); //getMethod(方法名,参数类型) Method m = personClass.getMethod("sayHello", String.class); System.out.println(m); //先实例化person类 Object obj = personClass.getConstructor().newInstance(); //invoke(要调用的对象,实参) m.invoke(obj, "hello world"); System.out.println("=获取私有的say方法="); //getDeclaredMethod(方法名,参数类型)可以用于获取私有方法(也能获取公有) 得解除私有限定 m = personClass.getDeclaredMethod("say", String.class); System.out.println(m); m.setAccessible(true);//解除私有限定 Object result = m.invoke(obj,"say hi"); //调用方法并获取返回值 System.out.println("返回值:" + result); //null 因为是void方法无返回 如果有返回类型将会有返回值 /** * 打印结果 * =获取所有公有方法= public java.lang.String reflect.Person.getName() public void reflect.Person.setName(java.lang.String) public java.lang.String reflect.Person.getWork() public java.lang.String reflect.Person.getSex() public void reflect.Person.setAge(java.lang.String) public java.lang.String reflect.Person.getAge() public void reflect.Person.setWork(java.lang.String) public void reflect.Person.setSex(java.lang.String) public void reflect.Person.sayHello(java.lang.String) public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public final void java.lang.Object.wait() throws java.lang.InterruptedException public boolean java.lang.Object.equals(java.lang.Object) public java.lang.String java.lang.Object.toString() public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll() =获取所有方法 包括私有= public java.lang.String reflect.Person.getName() public void reflect.Person.setName(java.lang.String) public java.lang.String reflect.Person.getWork() public java.lang.String reflect.Person.getSex() public void reflect.Person.setAge(java.lang.String) public java.lang.String reflect.Person.getAge() public void reflect.Person.setWork(java.lang.String) public void reflect.Person.setSex(java.lang.String) private void reflect.Person.say(java.lang.String) public void reflect.Person.sayHello(java.lang.String) =获取公有的Person()方法= public void reflect.Person.sayHello(java.lang.String) 公有,调用无参的构造方法 公有方法说的话->hello world =获取私有的say方法= private void reflect.Person.say(java.lang.String) 私有方法说的话->say hi 返回值:null */ } } 5.反射main方法 这边为了方便写两个类用作测试 //Test package reflect; public class Test { public static void main(String[] args) { System.out.println("执行了Test类里的main方法"); } } //TestMain package reflect; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Testmain { public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException, InvocationTargetException, IllegalAccessException { //1、获取Test对象的字节码 Class clazz = Class.forName("reflect.Test"); //2、获取main方法 getMethod(方法名,方法形参类型) Method methodMain = clazz.getMethod("main", String[].class); //3、调用main方法 //第一个参数,对象类型,static静态的可为null,第二个参数是String数组, methodMain.invoke(null, (Object)new String[]{}); //输出 执行了Test类里的main方法 } } 6.用于运行配置文件里的内容 本质也是先获取配置文件的内容之后,然后做相应实例化,调用方法等操作,比如说使用quartz需要配置quartz.properties name = garwer #经常看到一些jar包的配置文件在properties配置一些jar包路径 可能用于通过反射机制来实例化或者类加载用 也可记录方法名 类中的成员变量等 path = reflect.Person package reflect; import java.io.FileReader; import java.io.IOException; import java.util.Properties; public class testProperties { //通过key获取value值 private static String getVal(String key) throws IOException { Properties properties = new Properties(); FileReader in = new FileReader("src/main/resources/my.properties");//获取输入流 classpath: properties.load(in); in.close(); return properties.getProperty(key); } public static void main(String[] args) throws IOException, ClassNotFoundException { System.out.println(testProperties.class.getResource("").getPath()); System.out.println(getVal("name")); //输出garwer String path = getVal("path"); //reflect.Person System.out.println(path); Object o = Class.forName(path); System.out.println(o); //class reflect.Person } } 总结 反射主要用于在运行的时候,获取类的信息并操作它,广泛的用于在设计模式和jdk和各种框架中。

优秀的个人博客,低调大师

分布式系统的经典基础理论

历史优质文章: 可能是最漂亮的Spring事务管理详解 面试中关于Java虚拟机(jvm)的问题看这篇就够了 Java NIO 概览 分布式系统设计理念 分布式系统架构的第一原则是不要分布!这句话看似矛盾实则揭露了分布式系统的很多特征。 分布式系统的目标与要素 分布式系统的目标是提升系统的整体性能和吞吐量另外还要尽量保证分布式系统的容错性(假如增加10台服务器才达到单机运行效果2倍左右的性能,那么这个分布式系统就根本没有存在的意义)。 即使采用了分布式系统,我们也要尽力运用并发编程、高性能网络框架等等手段提升单机上的程序性能。 分布式系统设计两大思路:中心化和去中心化 1)中心化设计: 两个角色: 中心化的设计思想很简单,分布式集群中的节点机器按照角色分工,大体上氛围两种角色: “领导” 和 “干活的” 角色职责: “领导”通常负责分发任务并监督“干活的”,发现谁太闲了,就想发设法地给其安排新任务,确保没有一个“干活的”能够偷懒,如果“领导”发现某个“干活的”因为劳累过度而病倒了,则是不会考虑先尝试“医治”他的,而是一脚踢出去,然后把他的任务分给其他人。其中微服务架构 Kubernetes 就恰好采用了这一设计思路。 中心化设计的问题: 中心化的设计存在的最大问题是“领导”的安危问题,如果“领导”出了问题,则群龙无首,整个集群就奔溃了。但我们难以同时安排两个“领导”以避免单点问题。 中心化设计还存在另外一个潜在的问题,既“领导”的能力问题:可以领导10个人高效工作并不意味着可以领导100个人高效工作,所以如果系统设计和实现得不好,问题就会卡在“领导”身上。 领导安危问题的解决办法: 大多数中心化系统都采用了主备两个“领导”的设计方案,可以是热备或者冷备,也可以是自动切换或者手动切换,而且越来越多的新系统都开始具备自动选举切换“领导”的能力,以提升系统的可用性。 2)去中心化设计 终生地位平等: 在去中心化的设计里,通常没有“领导”和“干活的”这两种角色的区分,大家的角色都是一样的,地位是平等的,全球互联网就是一个典型的去中心化的分布式系统,联网的任意节点设备宕机,都只会影响很小范围的功能。 “去中心化”不是不要中心,而是由节点来自由选择中心。 (集群的成员会自发的举行“会议”选举新的“领导”主持工作。最典型的案例就是ZooKeeper及Go语言实现的Etcd) 去中心化设计的问题: 去中心化设计里最难解决的一个问题是 “脑裂”问题 ,这种情况的发声概率很低,但影响很大。脑裂问题,这种情况的发生概率很低,但影响很大。脑裂指一个集群犹豫网络的故障,被分为至少两个彼此无法通信的单独集群,此时如果两个集群都各自工作,则可能会产生眼中的数据冲突何错误。一般的设计思路是,当集群半段发声了脑裂问题是,规模较小的集群就“自杀”或者拒绝服务。 分布式与集群的区别是什么? 分布式: 一个业务分拆多个子业务,部署在不同的服务器上 集群: 同一个业务,部署在多个服务器上。比如之前做电商网站搭的redis集群以及solr集群都是属于将redis服务器提供的缓存服务以及solr服务器提供的搜索服务部署在多个服务器上以提高系统性能、并发量解决海量存储问题。 CAP定理 在理论计算机科学中,CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer's theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点: 一致性(Consistence) :所有节点访问同一份最新的数据副本 可用性(Availability):每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据 分区容错性(Partition tolerance) : 分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。 CAP仅适用于原子读写的NOSQL场景中,并不适合数据库系统。 注意:不是所谓的3选2(不要被网上大多数文章误导了): 现实生活中,大部分人解释这一定律时,常常简单的表述为:“一致性、可用性、分区容忍性三者你只能同时达到其中两个,不可能同时达到”。实际上这是一个非常具有误导性质的说法,而且在CAP理论诞生12年之后,CAP之父也在2012年重写了之前的论文。 当发生网络分区的时候,如果我们要继续服务,那么强一致性和可用性只能2选1。也就是说当网络分区之后P是前提,决定了P之后才有C和A的选择。也就是说分区容错性(Partition tolerance)我们是必须要实现的。 我在网上找了很多文章想看一下有没有文章提到这个不是所谓的3选2,用百度半天没找到了一篇,用谷歌搜索找到一篇比较不错的,如果想深入学习一下CAP就看这篇文章把,我这里就不多BB了:《分布式系统之CAP理论》 : http://www.cnblogs.com/hxsyl/p/4381980.html BASE理论 BASE理论由eBay架构师Dan Pritchett提出,在2008年上被分表为论文,并且eBay给出了他们在实践中总结的基于BASE理论的一套新的分布式事务解决方案。 BASE 是 Basically Available(基本可用) 、Soft-state(软状态) 和 Eventually Consistent(最终一致性) 三个短语的缩写。BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结,是基于CAP定理逐步演化而来的,它大大降低了我们对系统的要求。 BASE理论的核心思想 即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。也就是牺牲数据的一致性来满足系统的高可用性,系统中一部分数据不可用或者不一致时,仍需要保持系统整体“主要可用”。 针对数据库领域,BASE思想的主要实现是对业务数据进行拆分,让不同的数据分布在不同的机器上,以提升系统的可用性,当前主要有以下两种做法: 按功能划分数据库 分片(如开源的Mycat、Amoeba等)。 由于拆分后会涉及分布式事务问题,所以eBay在该BASE论文中提到了如何用最终一致性的思路来实现高性能的分布式事务。 BASE理论三要素 1. 基本可用 基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。但是,这绝不等价于系统不可用。 比如: 响应时间上的损失:正常情况下,一个在线搜索引擎需要在0.5秒之内返回给用户相应的查询结果,但由于出现故障,查询结果的响应时间增加了1~2秒 系统功能上的损失:正常情况下,在一个电子商务网站上进行购物的时候,消费者几乎能够顺利完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面 2. 软状态 软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时 3. 最终一致性 最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。 总结 本文主要是简单的介绍了三个常见的概念: 分布式系统设计理念 、 CAP定理 、 BASE理论 ,关于分布式系统的还有很多很多东西。 我是Snailclimb,一个以架构师为5年之内目标的小小白。欢迎关注我的微信公众号:"Java面试通关手册"(一个有温度的微信公众号,期待与你共同进步~~~坚持原创,分享美文,分享各种Java学习资源):

优秀的个人博客,低调大师

Java内存模型-Java内存模型的基础1

章节目录 1.并发编程需要解决的问题-线程间通信&线程间同步 2.Java内存模型的抽象结构 3.从源代码到指令序列的重排序 4.happens-before 简介 1.并发编程需要解决的问题-线程间通信&线程间同步 并发编程中需要处理两个关键问题:线程间通信、 线程间同步 线程之间通信机制分为两种:共享内存、消息传递共享内存通信与同步 操作类型 实现方式 通信 线程之间共享程序的公共状态,通过写-读内存中的变量的公共状态进行隐式通信 同步 显式进行同步,必须显式制定某个方法或某段代码需要在线程之间互斥执行 消息传递通信与同步 操作类型 实现方式 通信 线程之间没有公共状态,线程之间通过发送消息显式进行通信 同步 隐式进行同步,消息发送必须在消息发送之前 注意:java并发采用的是共享内存模型,java线程之间的通信总是隐式进行的。 2.Java内存模型的抽象结构 在Java中所有的实例对象、静态数据域、和数组元素都存储在堆内存当中,堆内存在线程之间是共享的。 -堆中数据域是线程共享的 局部变量、方法定义参数、和异常处理器参数不会在线程之间共享、他们不会有内存可见性问题,也不受内存模型的影响。-线程独享的 JMM简介 JMM决定一个线程对共享变量的写入何时对另一个线程可见。(可见性保证) 如下图所示: JMM内存模型抽象结构示意图 图示解释 1.线程之间共享的变量存储在主内存中,每个线程都有一个本地内存,本地内 存中存储了用共享内存中共享数据的副本。 线程A与线程B之间进行通信 1.线程A把本地内存A中更新过的共享变量刷新到主存中去 2.线程B到主存中去读取线程A之前已更新过的新的共享变量 JMM通过控制主内存与每个线程的本地内存之间的交互,来为Java程序员提供内存可见性保证。 3.从源代码到指令序列的重排序 重排序的作用 在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排序。 重排序类型 含义 编译器优化的重排序 编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序 指令级并行的重排序 不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序 内存系统的重排序 处理器采用缓存和读/写缓冲区,这使得加载和存储操作看起来是在乱序执行 对于处理器重排序,JMM处理器重排序规则要求java编译器在生成指令序列 时,插入特定类型的内存屏障指令,通过内存屏障指令禁止特定类型的处理器 重排序。 4.happens-before 简介 Java内存模型,使用happens-before的概念来阐述操作之间的内存可见性、 在JMM中,如果一个操作执行的结果需要对另一个操作可见、那么两个操作之间必须要存在happens-before(前一个操作的结果对后一个操作可见)关系。 与程序员密切相关的happens-before规则如下: 1.程序顺序规则:一个线程中的每个操作,happens-before于线程中的任意后续操作。 2.监视器锁规则:对一个锁的解锁,happens-before于随后对这个锁的加锁。 3.volatile规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。 4.传递性:如果A操作happens-beforeB,且B happens-before C,那么A happens-before C。

优秀的个人博客,低调大师

Java基础6:代码块与代码加载顺序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a724888/article/details/80069472 这位大侠,这是我的公众号:程序员江湖。 分享程序员面试与技术的那些事。 干货满满,关注就送。 本文主要介绍了三种代码块的特性和使用方法。 具体代码在我的GitHub中可以找到 https://github.com/h2pl/MyTech 文章首发于我的个人博客: https://h2pl.github.io/2018/04/24/javase6 代码块:用{}包围的代码 java中的代码块按其位置划分为四种: 局部代码块 位置:局部位置(方法内部) 作用:限定变量的生命周期,尽早释放,节约内存 调用:调用其所在的方法时执行 public class 局部代码块 { @Test public void test (){ B b = new B(); b.go(); } } class B { B(){} public void go() { //方法中的局部代码块,一般进行一次性地调用,调用完立刻释放空间,避免在接下来的调用过程中占用栈空间 //因为栈空间内存是有限的,方法调用可能会会生成很多局部变量导致栈内存不足。 //使用局部代码块可以避免这样的情况发生。 { int i = 1; ArrayList<Integer> list = new ArrayList<>(); while (i < 1000) { list.add(i ++); } for (Integer j : list) { System.out.println(j); } System.out.println("gogogo"); } System.out.println("hello"); } } 构造代码块 位置:类成员的位置,就是类中方法之外的位置 作用:把多个构造方法共同的部分提取出来,共用构造代码块 调用:每次调用构造方法时,都会优先于构造方法执行,也就是每次new一个对象时自动调用,对 对象的初始化 class A{ int i = 1; int initValue;//成员变量的初始化交给代码块来完成 { //代码块的作用体现于此:在调用构造方法之前,用某段代码对成员变量进行初始化。 //而不是在构造方法调用时再进行。一般用于将构造方法的相同部分提取出来。 // for (int i = 0;i < 100;i ++) { initValue += i; } } { System.out.println(initValue); System.out.println(i);//此时会打印1 int i = 2;//代码块里的变量和成员变量不冲突,但会优先使用代码块的变量 System.out.println(i);//此时打印2 //System.out.println(j);//提示非法向后引用,因为此时j的的初始化还没开始。 // } { System.out.println("代码块运行"); } int j = 2; { System.out.println(j); System.out.println(i);//代码块中的变量运行后自动释放,不会影响代码块之外的代码 } A(){ System.out.println("构造方法运行"); } } public class 构造代码块 { @Test public void test() { A a = new A(); } } 静态代码块 位置:类成员位置,用static修饰的代码块 作用:对类进行一些初始化 只加载一次,当new多个对象时,只有第一次会调用静态代码块,因为,静态代码块 是属于类的,所有对象共享一份 调用: new 一个对象时自动调用 public class 静态代码块 { @Test public void test() { C c1 = new C(); C c2 = new C(); //结果,静态代码块只会调用一次,类的所有对象共享该代码块 //一般用于类的全局信息初始化 //静态代码块调用 //代码块调用 //构造方法调用 //代码块调用 //构造方法调用 } } class C{ C(){ System.out.println("构造方法调用"); } { System.out.println("代码块调用"); } static { System.out.println("静态代码块调用"); } } 执行顺序 静态代码块 —–> 构造代码块 ——-> 构造方法 关于抽象类和接口的内容可以在上一节查看: https://blog.csdn.net/a724888/article/details/80061047 关于Java类和包的内容可以在下一节查看: https://blog.csdn.net/a724888/article/details/80069504

优秀的个人博客,低调大师

第187天:js基础---常见的Bom对象

BOM(Browser Object Mode)浏览器对象模型,是Javascript的重要组成部分。它提供了一系列对象用于与浏览器窗口进行交互,这些对象通常统称为BOM。 一张图了解一下先 1、window 对象——BOM核心 window,顾名思义,窗口对象。它表示整个浏览器窗口,主要用来操作浏览器窗口。同时, window对象还是 ECMAScript 中的 Global 对象,因而所有全局变量和函数都是它的属性,且所有原生的构造函数及其他函数也都存在于它的命名空间下。 弹框类的方法。前面省略window alert('提示信息') confirm("确认信息") prompt("弹出输入框") open("url地址",“_black或_self”,“新窗口的大小”) close() 关闭当前的网页 定时器,清除定时器。 setTimeout(函数,时间) 只执行一次 clearTimeout(定时器名称) 清除定时器,用于停止执行setTimeout()方法的函数代码。 setInterval(函数,时间) 无限执行 clearInterval() 方法用于停止 setInterval() 方法执行的函数代码。 Cookies 用于存储 web 页面的用户信息。 JavaScript 可以使用document.cookie属性来创建 、读取、及删除 cookies。document.cookie 将以字符串的方式返回所有的 cookies,类型格式: cookie1=value; cookie2=value; cookie3=value; 2、document 对象 它是window对象的一个属性,可以用来处理页面文档 3、location 对象 对象用于获得当前页面的地址 (URL),并把浏览器重定向到新的页面。 window.location对象在编写时可不使用 window 这个前缀。 一些例子: location.herf = 'url地址' location.hostname 返回 web 主机的域名 location.pathname 返回当前页面的路径和文件名 location.port 返回 web 主机的端口 (80 或 443) location.portocol 返回页面使用的web协议。 http:或https: 4、navigator 对象 对象提供了与浏览器有关的信息。userAgent是最常用的属性,用来完成浏览器判断。 window.navigator对象在编写时可不使用 window 这个前缀。 5、screen 对象 主要用来获取用户的屏幕信息。 window.screen对象在编写时可以不使用 window 这个前缀 height: 获取整个屏幕的高。 width : 获取整个屏幕的宽。 availHeight: 整个屏幕的高减去系统部件的高(可用的屏幕宽度) availWidth : 整个屏幕的宽减去系统部件的宽(可用的屏幕高度) 6、history 对象 对象包含浏览器的历史。 window.history对象在编写时可不使用 window 这个前缀。 back() 返回上一页。 forward() 返回下一页。 go(“参数”) -1表示上一页,1表示下一页。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册