- 枚舉類中定義方法
enum S{
D(1){
public void f1(){System.out.println("ddd");}
}
private int i;
S(int i){
this.i = i;
}
public void f1(){
System.out.println("sss");
}; }
public static void main(String[] args) {
S.D.f1();
}
輸出 ddd,
2.synchronized 和 ReentrantLock
模擬生產者和消費者模式
生產者
import lombok.SneakyThrows;
import java.util.concurrent.TimeUnit;
public class Pro {
@SneakyThrows
public void product(){
System.out.println("生產者在生產。。。");
TimeUnit.SECONDS.sleep((long)1);
System.out.println("生產者生產結束");
}
}
消費者
```java
import lombok.SneakyThrows;
import java.util.concurrent.TimeUnit;
public class Cosu {
@SneakyThrows
public void consume(){
System.out.println("消費者在消費。。。");
TimeUnit.SECONDS.sleep((long)1);
System.out.println("消費者消費結束");
}
}
```java
synchronized版本
Object lock = new Object();
//消費者
new Thread(()->{
try{
synchronized (lock){
System.out.println("進入消費者");
lock.wait();
new Cosu().consume();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
//確保消費者早於生產者啓動
TimeUnit.SECONDS.sleep((long)1);
//生產者生產,生產結束後通知消費者
new Thread(new Runnable() {
@Override
public void run() {
try{
synchronized (lock){
System.out.println("進入生產者");
new Pro().product();
lock.notify();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
ReentrantLock版本
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
new Thread(()->{
try{
lock.lock();
System.out.println("進入消費者");
condition.await();
new Cosu().consume();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}).start();
//確保消費者早於生產者啓動
TimeUnit.SECONDS.sleep((long)1);
//生產者生產,生產結束後通知消費者
new Thread(new Runnable() {
@Override
public void run() {
try{
lock.lock();
System.out.println("進入生產者");
new Pro().product();
condition.signalAll();
} finally{
lock.unlock();
}
}
}).start();
3.包權限
【只有】public類對包外可見;
不管父類子類是否在一個包,子類總能訪問父類protected方法;
不同的包下,不能訪問實例的protected方法;
在a包裏的A類中的aa方法不能調用b包下B【實例】的protected方法bb
package com.talent.util;
public class TestProtect {
protected void p(){}
}
//同一個包下的子類可以訪問
package com.talent.util;
public class TestProtectImpl extends TestProtect{
protected void pp(){
p();//在【類】中可以訪問父類protected方法
}
public static void main(String[] args) {
new TestProtectImpl().p();
new TestProtectImpl().pp();
new TestProtect().p();
}
}
//不同包中
package com.talent.user;
import com.talent.util.TestProtect;
import com.talent.util.TestProtectImpl;
public class UserA {
protected void proUserA(){
new TestProtectImpl().pp();//注意,這是不允許的
}
}
class ImplTestProtectedInAnotherPackage extends TestProtect {
protected void d(){
p();//雖然子類和父類不在同一個包,但在【類】中依然可以訪問父類protected方法
}
}
函数编程
@FunctionalInterface
interface Converter<F, T> {
//T 是返回值,F是参数
T convert(F from);
}
class Something {
String startsWith(String s) {
return String.valueOf(s.charAt(0));
}
Integer endWith(String s){
return Integer.valueOf(s);
}
public static void main(String[] args) {
Something something = new Something();
Converter<String, String> converter1 = something::startsWith;
Converter<String,Integer> converter2 = something::endWith;
String converted = converter1.convert("Java");
System.out.println(converted); // "J"
}
}
常见的函数编程接口
class Person{
private String firstName;
private String lastName;
public Person(String f,String l){
this.firstName = f;
this.lastName = l;
}
@Override
public String toString() {
return "Person{" +
"firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
class Lambda4 {
//String代表入参类型,Predicate返回布尔值
static Predicate<String> isEmpty = String::isEmpty;
static Predicate<String> isW = s->s.equals("w");
//泛型参数String代表入参类型,Integer代表返回值类型
static Function<String, Integer> toInteger = Integer::valueOf;
//backToString第一个泛型参数类型 要和toInteger的入参类型一致,andThen中参数类型是toInteger的【返回值】
static Function<String, String> backToString = toInteger.andThen(integer -> String.valueOf(integer));
static Function<String,Person> stringToPerson = backToString.andThen(s -> new Person(String.valueOf(s),String.valueOf(s)));
static Function<String,Person> function1 = s -> Optional.of(new Person(s,s)).get();
static Function<String,Person> function2 = function1.andThen(person -> person);
//Person代表入参类型,Consumer没有返回值
static Consumer<Person> consumer1 = person -> person.getFirstName();
//consumer2的泛型参数和consumer1的要一致,andThen中的参数是consumer1的【入参】
static Consumer<Person> consumer2 = consumer1.andThen(s->System.out.println(s));
static Comparator<Person> comparator = (p1, p2) -> p1.getFirstName().compareTo(p2.getFirstName());
}
finally
finally中的return语句优先级最高;
若try中有return语句,finally中对返回结果进行修改,则修改内容不会返回。
static int tryAndFinally(){
int a=0;
try{
++a;
return a;
}finally {
a=10;//修改结果不会返回
System.out.println("finally");
}
}
public static void main(String[] args) {
System.out.println(tryAndFinally());
}
输入url并回车就是DNS解析和建立tcp连接的过程。
为什么重载equals同时重载hash?
两个Java对象相等,则hash值必须相等;!!!
两个Java对象hash相等,这两个对象可以不相等;
equals比较内容,hash比较是比较本质(比如对象的存储地址,对象的字段等);
如果只重写了equals,那么可能出翔这种情况:
两个对象相等->equals,hash值却不相等
2020-01-23
32、64位系统有什么区别
主要是对寻址能力不同,即对指令的处理速度差异
https://www.cnblogs.com/zhishiyv/p/9683323.html
内存寻址
https://blog.csdn.net/xhumble/article/details/105652695
https://blog.csdn.net/tristacrystal/article/details/84028834
MySQL用B+树不用hash表做索引的原因
hash表不支持范围、模糊;如果hash碰撞很严重,hash表会变成链表
为什么建议使用主键自增的索引?
B+树是有序的,主键是递增的,就不会出现页分裂
如何正确地终止线程
不仅需要调用中断方法,还需要提供中断逻辑,否则,线程不会中断,会继续执行下去。
https://blog.csdn.net/xzp_12345/article/details/81131026
如何解决hash碰撞
1-开放地址法:所有元素会存到开辟的空间
2-链表法:元素会存到联表中,联表头地址存到开辟的空间
https://www.jianshu.com/p/35ece8281890
https://blog.csdn.net/zhuwukai/article/details/77248074
https://blog.csdn.net/qq_35583089/article/details/80048285?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3.not_use_machine_learn_pai&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3.not_use_machine_learn_pai
HashMap初始大小为什么是16
元素存入hash表中要对表长度取余,16是2的4次方,可以用位运算,加快速度
单链表长度>=8 && 数组总长度>=64(即经过两次扩容),才会把单链表转成红黑树
final void treeifyBin(Node<K,V>[] tab, int hash) {
int n, index; Node<K,V> e;
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)//64
resize();
HashMap的put
1-通过hash值计算数组位置,注意这里的hash不是直接调用key.hashCode(),而是使用了HashMap的hash函数
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
在HashMap中只要两个键的hash值相同,或者两个键equals,就认为这两个键相同
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
2-判断该位置是否有元素,没有就新建一个节点;有就
2-1还是先和第一个比较,hash值一致或者key 相等(equals)就替换
2-2如果该位置是树,则添加树节点
2-3如果第一个没匹配,又不是树,则遍历链表,加到链表末端,或者替换旧值
3-添加之后,判断是否需要扩容
HashMap不安全表现在哪
1-多线程的put可能导致元素的丢失
// 新建节点并追加到链表
if ((e = p.next) == null) { // #1
p.next = newNode(hash, key, value, null); // #2
如果两个线程都走到#1,p.next就会被赋值两次,导致第一次赋值被覆盖
2-put和get并发时,可能导致get为null
如果put后,需要扩容,扩容时会产生一个空数组,如果此时其他线程get,就会得到null值
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; // #1
table = newTab; // #2
ConcurrentHashMap怎么解决线程安全问题呢
1-Node节点中的value用volatile修饰
2-针对HashMap中值覆盖问题采用cas解决
线程1和线程2都走到了#1,假设线程1先赋值,线程2赋值时,发现oldVal变化了就会返回失败
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
3-同步逻辑使用synchronized
在Spring中FactoryBean和BeanFactory有什么区别呢
BeanFactory是IOC容器顶层接口,提供了IOC容器应遵守的的最基本的接口
ApplicationContext就是他的一个实现类
FactoryBean可以通过反射生产Bean
简言之,BeanFactory管理Bean,FactoryBean生产Bean.
https://zhuanlan.zhihu.com/p/124119677
https://www.jianshu.com/p/5ab6643186b3
String和Integer都有缓存,String缓存在常量池,减少了重复对象的创建;
Integer默认缓存-128到127
他们都应该用equals比较,再就是注意equals默认实现是==
怎么解决幻读
MySQL通过MVCC解决了不可重复读;
在MVCC的基础上,手动加锁可以解决幻读。
select for update加排他锁(X锁),其他事物的读写都会被阻塞;select lock in share mode加读共享锁(S锁),其他事务的读不会被阻塞,写会被阻塞。
幻读:
事务A 事务B
select * from user where id= 1;
empty;
insert into user values(1,‘zcx’);
insert into user values(1,‘xxx’);//报重复键
不可重复读是通过读来验证;幻读是通过写来验证;
进程、线程和协程
进程VS线程
1-进程切换更消耗资源
2-多进程程序更健壮(程序中一个进程死了,不会影响其他进程,多线程程序一个进程死了,进程内的所有线程都死了)
3-线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据。
线程和协程
1-线程切换有上下文切换(用户状态和内核状态的切换),协程只有用户状态
2-一个线程内部从结果来看是顺序执行的,协程可以不按照顺序执行,可以“来回执行”
进程通信https://blog.csdn.net/weixin_34135138/article/details/112666445
深拷贝、浅拷贝
浅拷贝:被复制对象的所有值属性都含有与原来对象的相同(这部分是深拷贝),而所有的对象引用属性仍然指向原来的对象(这部分是浅拷贝)。
深拷贝:在浅拷贝的基础上,所有引用其他对象的变量也进行了clone,并指向被复制过的新对象。
@Data
public class Person implements Cloneable {
private String name;
private Integer age;
private Address address;
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj=super.clone();
Address a=((Person)obj).getAddress();
//注意这里,set进去的是拷贝
((Person)obj).setAddress((Address) a.clone());
return obj;
}
}
mysql主从复制如何解决复制延迟问题
造成延迟的原因:
1-从库SQL线程重放是随机写盘的,就是虽然binlog已经同步到从库,但sql线程还没有把数据写入磁盘,即重放不及时。
2-主库高并发,导致sql线程同步不及时
3-重放过程中如果遇到锁等待,也会造成延迟
解决方案
1-从库并行同步(MySQL5.6版本以后)
2-对于实时性要求高的数据,读主库