2024年Java最全多线程高并发,如何用分库分表的9种分布式主键ID生成方案

本文详细介绍了Java多线程及并发编程的基础,包括线程的创建、多进程与多线程的区别,以及线程的实现方式。此外,还探讨了在分布式环境下,如何通过九种不同的方案解决分库分表后的主键ID生成问题,为Java工程师提供了宝贵的面试和学习资料。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

总结

机会是留给有准备的人,大家在求职之前应该要明确自己的态度,熟悉求职流程,做好充分的准备,把一些可预见的事情做好。

对于应届毕业生来说,校招更适合你们,因为绝大部分都不会有工作经验,企业也不会有工作经验的需求。同时,你也不需要伪造高大上的实战经验,以此让自己的简历能够脱颖而出,反倒会让面试官有所怀疑。

你在大学时期应该明确自己的发展方向,如果你在大一就确定你以后想成为Java工程师,那就不要花太多的时间去学习其他的技术语言,高数之类的,不如好好想着如何夯实Java基础。下图涵盖了应届生乃至转行过来的小白要学习的Java内容:

请转发本文支持一下

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

这就是 NIO 模型的思路,也是 NIO 模型比 BIO 模型效率高很多的原因,我们之后再讲。

线程 thread

线程,是一个进程里的具体的执行路径,就是真正干活的。

在一个进程里,一个时间片也只能有一个线程在执行,但因为时间片的切换速度非常快,所以看起来就好像是同时进行的。

一个进程里至少有一个线程。比如主线程,就是我们平时写的 main() 函数,是用户线程;还有 gc 线程是 JVM 生产的,负责垃圾回收,是守护线程

每个线程有自己的 stack,记录该线程里面的方法相互调用的关系;

但是一个进程里的所有线程是共用堆 heap 的。

那么不同的进程之间是不可以互相访问内存的,每个进程有自己的内存空间 memeory space,也就是虚拟内存 virtual memory

通过这个虚拟内存,每一个进程都感觉自己拥有了整个内存空间。

虚拟内存的机制,就是屏蔽了物理内存的限制。

Q:那如果物理内存被用完了呢?

用硬盘,比如 windows 系统的分页文件,就是把一部分虚拟内存放到了硬盘上。

相应的,此时程序运行会很慢,因为硬盘的读写速度比内存慢很多,是我们可以感受到的慢,这就是为什么开多了程序电脑就会变卡的原因。

Q:那这个虚拟内存是有多大呢?

对于 64 位操作系统来说,每个程序可以用 64 个二进制位,也就是 2^64 这么大的空间!

如果还不清楚二进制相关内容的,公众号内回复「二进制」获取相应的文章哦~

总结

总结一下,在一个时间片里,一个 CPU 只能执行一个进程。

CPU 给某个进程分配资源后,这个进程开始运行;进程里的线程去抢占资源,一个时间片就只有一个线程能执行,谁先抢到就是谁的。

多进程 vs 多线程

每个进程是独立的,进程 A 出问题不会影响到进程 B;

虽然线程也是独立运行的,但是一个进程里的线程是共用同一个堆,如果某个线程 out of memory,那么这个进程里所有的线程都完了。

所以多进程能够提高系统的容错性 fault tolerance ,而多线程最大的好处就是线程间的通信非常方便。

进程之间的通信需要借助额外的机制,比如进程间通讯 interprocess communication - IPC,或者网络传递等等。

如何创建线程

上面说了一堆概念,接下来我们看具体实现。

Java 中是通过 java.lang.Thread 这个类来实现多线程的功能的,那我们先来看看这个类。

从文档中我们可以看到,Thread 类是直接继承 Object 的,同时它也是实现了 Runnable 接口。

官方文档里也写明了 2 种创建线程的方式:

一种方式是从 Thread 类继承,并重写 run()run() 方法里写的是这个线程要执行的代码;

启动时通过 new 这个 class 的一个实例,调用 start() 方法启动线程。

二是实现 Runnable 接口,并实现 run()run() 方法里同样也写的是这个线程要执行的代码;

稍有不同的是启动线程,需要 new 一个线程,并把刚刚创建的这个实现了 Runnable 接口的类的实例传进去,再调用 start(),这其实是代理模式

如果面试官问你,还有没有其他的,那还可以说:

  1. 实现 Callable 接口

  2. 通过线程池来启动一个线程。

但其实,用线程池来启动线程时也是用的前两种方式之一创建的。

这两种方式在这里就不细说啦,我们具体来看前两种方式。

继承 Thread 类

`public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(“小齐666:” + i);
}
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
for (int i = 0; i < 100; i++) {
System.out.println(“主线程” + i + “:齐姐666”);
}
}
}

在这里,

  • main 函数是主线程,是程序的入口,执行整个程序;

  • 程序开始执行后先启动了一个新的线程 myThread,在这个线程里输出“小齐”;

  • 主线程并行执行,并输出“主线程i:齐姐”。

来看下结果,就是两个线程交替夸我嘛~

Q:为啥和我运行的结果不一样?

多线程中,每次运行的结果可能都会不一样,因为我们无法人为控制哪条线程在什么时刻先抢到资源。

当然了,我们可以给线程加上优先级 priority,但高优先级也无法保证这条线程一定能先被执行,只能说有更大的概率抢到资源先执行。

实现 Runnable 接口

这种方式用的更多。

`public class MyRunnable implements Runnable {
@Override
public void run() {
for(int i = 0; i < 100; i++) {
System.out.println(“小齐666:” + i);
}
}

public static void main(String[] args) {
new Thread(new MyRunnable()).start();

那么如何才能正确的掌握Redis呢?

为了让大家能够在Redis上能够加深,所以这次给大家准备了一些Redis的学习资料,还有一些大厂的面试题,包括以下这些面试题

  • 并发编程面试题汇总

  • JVM面试题汇总

  • Netty常被问到的那些面试题汇总

  • Tomcat面试题整理汇总

  • Mysql面试题汇总

  • Spring源码深度解析

  • Mybatis常见面试题汇总

  • Nginx那些面试题汇总

  • Zookeeper面试题汇总

  • RabbitMQ常见面试题汇总

JVM常频面试:

Redis高频面试笔记:基础+缓存雪崩+哨兵+集群+Reids场景设计

Mysql面试题汇总(一)

Redis高频面试笔记:基础+缓存雪崩+哨兵+集群+Reids场景设计

Mysql面试题汇总(二)

Redis高频面试笔记:基础+缓存雪崩+哨兵+集群+Reids场景设计

Redis常见面试题汇总(300+题)

Redis高频面试笔记:基础+缓存雪崩+哨兵+集群+Reids场景设计

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

img-flpbBLvX-1714886255720)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值