先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
正文
clientChannel.read(buf);//
buf.put(b);
clientChannel.register(selector, SelectionKey.OP_WRITE, buf);//注册写事件
}
} catch(Throwable e) {
e.printStackTrace();
System.out.println(“客户端主动断开连接。。。。。。。”);
ssc.register(selector, SelectionKey.OP_ACCEPT);
}
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Nio客户端代码:
package threadmode.r1;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
/**
-
@author dingwei2
*/
public class NioClient {
public static void main(String[] args) {
// TODO Auto-generated method stub
SocketChannel clientClient;
Selector selector = null;
try {
clientClient = SocketChannel.open();
clientClient.configureBlocking(false);
selector = Selector.open();
clientClient.register(selector, SelectionKey.OP_CONNECT);
clientClient.connect(new InetSocketAddress(“127.0.0.1”,9080));
Set ops = null;
while(true) {
try {
selector.select();
ops = selector.selectedKeys();
for (Iterator it = ops.iterator(); it.hasNext()😉 {
SelectionKey key = it.next();
it.remove();
if(key.isConnectable()) {
System.out.println(“client connect”);
SocketChannel sc = (SocketChannel) key.channel();
// 判断此通道上是否正在进行连接操作。
// 完成套接字通道的连接过程。
if (sc.isConnectionPending()) {
sc.finishConnect();
System.out.println(“完成连接!”);
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put(“Hello,Server”.getBytes());
buffer.flip();
sc.write(buffer);
}
sc.register(selector, SelectionKey.OP_READ);
} else if(key.isWritable()) {
System.out.println(“客户端写”);
SocketChannel sc = (SocketChannel)key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put(“hello server.”.getBytes());
buffer.flip();
sc.write(buffer);
} else if(key.isReadable()) {
System.out.println(“客户端收到服务器的响应…”);
SocketChannel sc = (SocketChannel)key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int count = sc.read(buffer);
if(count > 0 ) {
buffer.flip();
byte[] response = new byte[buffer.remaining()];
buffer.get(response);
System.out.println(new String(response));
}
}
}
} catch(Throwable e) {
e.printStackTrace();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
1.2 多线程模型
=========
Reactor多线程模型(多个Nio线程处理网络读写)(此图来源与网络)。
多线程模型,就是1个线程Acceptor接受客户端的连接,然后由一组IO线程(Reactor)来执行网络的读写。下面贴出其实现。
其中NioServer中的Acceptor为接受客户端连接线程。
其中NioReactorThreadGroup为一组IO线程,NioReactorThread为具体IO线程的实现。
package threadmode.r2;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NioServer {
public static void main(String[] args) {
// TODO Auto-generated method stub
new Thread(new Acceptor()).start();
}
/**
-
连接线程模型,反应堆,转发器 Acceptor
-
@author dingwei2
*/
private static final class Acceptor implements Runnable {
private NioReactorThreadGroup nioReactorThreadGroup;
public Acceptor() {
nioReactorThreadGroup = new NioReactorThreadGroup();
}
public void run() {
// TODO Auto-generated method stub
System.out.println(“服务端启动成功,等待客户端接入”);
ServerSocketChannel ssc = null;
Selector selector = null;
try {
ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ssc.bind(new InetSocketAddress(“127.0.0.1”, 9080));
selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
Set ops = null;
while (true) {
try {
selector.select(); // 如果没有感兴趣的事件到达,阻塞等待
ops = selector.selectedKeys();
} catch (Throwable e) {
e.printStackTrace();
break;
}
// 处理相关事件
for (Iterator it = ops.iterator(); it.hasNext()😉 {
SelectionKey key = it.next();
it.remove();
try {
if (key.isAcceptable()) { // 客户端建立连接
System.out.println(“收到客户端的连接请求。。。”);
ServerSocketChannel serverSc = (ServerSocketChannel) key.channel();// 这里其实,可以直接使用ssl这个变量
SocketChannel clientChannel = serverSc.accept();
clientChannel.configureBlocking(false);
nioReactorThreadGroup.dispatch(clientChannel); // 转发该请求
}
} catch (Throwable e) {
e.printStackTrace();
System.out.println(“客户端主动断开连接。。。。。。。”);
}
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
package threadmode.r2;
import java.nio.channels.SocketChannel;
import java.util.concurrent.atomic.AtomicInteger;
/**
-
nio 线程组;简易的NIO线程组
-
@author dingwei2
*/
public class NioReactorThreadGroup {
private static final AtomicInteger requestCounter = new AtomicInteger(); //请求计数器
private final int nioThreadCount; // 线程池IO线程的数量
private static final int DEFAULT_NIO_THREAD_COUNT;
private NioReactorThread[] nioThreads;
static {
// DEFAULT_NIO_THREAD_COUNT = Runtime.getRuntime().availableProcessors() > 1
// ? 2 * (Runtime.getRuntime().availableProcessors() - 1 ) : 2;
DEFAULT_NIO_THREAD_COUNT = 4;
}
public NioReactorThreadGroup() {
this(DEFAULT_NIO_THREAD_COUNT);
}
public NioReactorThreadGroup(int threadCount) {
if(threadCount < 1) {
threadCount = DEFAULT_NIO_THREAD_COUNT;
}
this.nioThreadCount = threadCount;
this.nioThreads = new NioReactorThread[threadCount];
for(int i = 0; i < threadCount; i ++ ) {
this.nioThreads[i] = new NioReactorThread();
this.nioThreads[i].start(); //构造方法中启动线程,由于nioThreads不会对外暴露,故不会引起线程逃逸
}
System.out.println(“Nio 线程数量:” + threadCount);
}
public void dispatch(SocketChannel socketChannel) {
if(socketChannel != null ) {
next().register(socketChannel);
}
}
protected NioReactorThread next() {
return this.nioThreads[ requestCounter.getAndIncrement() % nioThreadCount ];
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
package threadmode.r2;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
/**
-
Nio 线程,专门负责nio read,write
-
本类是实例行代码,不会对nio,断线重连,写半包等场景进行处理,旨在理解 Reactor模型(多线程版本)
-
@author dingwei2
*/
public class NioReactorThread extends Thread {
private static final byte[] b = “hello,服务器收到了你的信息。”.getBytes(); //服务端给客户端的响应
private Selector selector;
private List waitRegisterList = new ArrayList(512);
private ReentrantLock registerLock = new ReentrantLock();
public NioReactorThread() {
try {
this.selector = Selector.open();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
-
socket channel
-
@param socketChannel
*/
public void register(SocketChannel socketChannel) {
if(socketChannel != null ) {
try {
registerLock.lock();
waitRegisterList.add(socketChannel);
} finally {
registerLock.unlock();
}
}
}
//private
public void run() {
while(true) {
Set ops = null;
try {
selector.select(1000);
ops = selector.selectedKeys();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
continue;
}
//处理相关事件
for (Iterator it = ops.iterator(); it.hasNext()😉 {
SelectionKey key = it.next();
it.remove();
try {
if (key.isWritable()) { //向客户端发送请求
SocketChannel clientChannel = (SocketChannel)key.channel();
ByteBuffer buf = (ByteBuffer)key.attachment();
buf.flip();
clientChannel.write(buf);
System.out.println(“服务端向客户端发送数据。。。”);
//重新注册读事件
clientChannel.register(selector, SelectionKey.OP_READ);
} else if(key.isReadable()) { //接受客户端请求
System.out.println(“服务端接收客户端连接请求。。。”);
SocketChannel clientChannel = (SocketChannel)key.channel();
ByteBuffer buf = ByteBuffer.allocate(1024);
System.out.println(buf.capacity());
clientChannel.read(buf);//
buf.put(b);
clientChannel.register(selector, SelectionKey.OP_WRITE, buf);//注册写事件
}
} catch(Throwable e) {
e.printStackTrace();
System.out.println(“客户端主动断开连接。。。。。。。”);
}
}
//注册事件
if(!waitRegisterList.isEmpty()) {
try {
registerLock.lock();
for (Iterator it = waitRegisterList.iterator(); it.hasNext()😉 {
SocketChannel sc = it.next();
try {
sc.register(selector, SelectionKey.OP_READ);
} catch(Throwable e) {
e.printStackTrace();//ignore
}
it.remove();
}
} finally {
registerLock.unlock();
}
}
}
}
}
NioClient与Reactor,单线程版本一样,在这不重复给出。
上述示例代码中,其实并不是完成按照Reacor设计模式而来的,重头戏请看1.3,主从多线程模型(Reacor)实现
1.3 主从多线程模型(Reactor)
====================
主从多线程模型(此图来源与网络)
重点关注点如下:
-
Acceeptor:职责维护java.nio.ServerSocketChannel类,绑定服务端监听端口,然后将该通道注册到MainRector中;
-
Main Reactor,监听客户端连接的反应堆,这里使用jdk并发中的Executors.newSingleThreadExecutor线程池来实现,监听客户端的连接事件(OP_ACCEPT)
-
Sub Reactor,目前没有使用jdk的并发池,这里用的SubReactorThreadGroup,其实现是数组,当然这里也可以使用jdk线程池,SubReactor的每一个线程都是IO线程,用来处理读,写事件。所有的IO线程公用一个业务线程池(基于juc)实现,用来处理业务逻辑,也就是运行Handel的地方。
Handel:具体业务逻辑实现,本例就是获取客户端的信息后,在请求信息后面追加一段文字,便返回给客户端。相关源码实现:
NioServer(Acceptor)的实现源码:
package persistent.prestige.demo.netty.threadmode.t3;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
-
Reactor 主从Reactor模式实现
-
Acceptor,其实个人认为,这里就是服务端角色
-
@author Administrator
*/
public class NioServer {
private static final int DEFAULT_PORT = 9080;
public static void main(String[] args) {
new Thread(new Acceptor()).start();
}
private static class Acceptor implements Runnable {
// main Reactor 线程池,用于处理客户端的连接请求
private static ExecutorService mainReactor = Executors.newSingleThreadExecutor();
public void run() {
// TODO Auto-generated method stub
ServerSocketChannel ssc = null;
try {
ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ssc.bind(new InetSocketAddress(DEFAULT_PORT));
//转发到 MainReactor反应堆
dispatch(ssc);
System.out.println(“服务端成功启动。。。。。。”);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void dispatch(ServerSocketChannel ssc) {
mainReactor.submit(new MainReactor(ssc));
}
}
}
MainReactor 源码如下:
package persistent.prestige.demo.netty.threadmode.t3;
import java.io.IOException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
/**
-
主Reactor,主要用来处理连接请求的反应堆
-
@author Administrator
*/
public class MainReactor implements Runnable {
private Selector selector;
private SubReactorThreadGroup subReactorThreadGroup;
public MainReactor(SelectableChannel channel) {
try {
selector = Selector.open();
channel.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
subReactorThreadGroup = new SubReactorThreadGroup(4);
}
public void run() {
System.out.println(“MainReactor is running”);
// TODO Auto-generated method stub
while (!Thread.interrupted()) {
Set ops = null;
try {
selector.select(1000);
ops = selector.selectedKeys();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 处理相关事件
for (Iterator it = ops.iterator(); it.hasNext()😉 {
SelectionKey key = it.next();
it.remove();
try {
if (key.isAcceptable()) { // 客户端建立连接
System.out.println(“收到客户端的连接请求。。。”);
ServerSocketChannel serverSc = (ServerSocketChannel) key.channel();// 这里其实,可以直接使用ssl这个变量
SocketChannel clientChannel = serverSc.accept();
clientChannel.configureBlocking(false);
subReactorThreadGroup.dispatch(clientChannel); // 转发该请求
}
} catch (Throwable e) {
e.printStackTrace();
System.out.println(“客户端主动断开连接。。。。。。。”);
}
}
}
}
}
SubReactor组,IO线程池实现:
package persistent.prestige.demo.netty.threadmode.t3;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
/**
-
nio 线程组;简易的NIO线程组
-
@author dingwei2
*/
public class SubReactorThreadGroup {
private static final AtomicInteger requestCounter = new AtomicInteger(); //请求计数器
private final int nioThreadCount; // 线程池IO线程的数量
private static final int DEFAULT_NIO_THREAD_COUNT;
private SubReactorThread[] nioThreads;
private ExecutorService businessExecutePool; //业务线程池
static {
// DEFAULT_NIO_THREAD_COUNT = Runtime.getRuntime().availableProcessors() > 1
// ? 2 * (Runtime.getRuntime().availableProcessors() - 1 ) : 2;
DEFAULT_NIO_THREAD_COUNT = 4;
}
public SubReactorThreadGroup() {
this(DEFAULT_NIO_THREAD_COUNT);
}
public SubReactorThreadGroup(int threadCount) {
写在最后
学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!
最后再分享的一些BATJ等大厂20、21年的面试题,把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。
Mybatis面试专题
MySQL面试专题
并发编程面试专题
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
private static final AtomicInteger requestCounter = new AtomicInteger(); //请求计数器
private final int nioThreadCount; // 线程池IO线程的数量
private static final int DEFAULT_NIO_THREAD_COUNT;
private SubReactorThread[] nioThreads;
private ExecutorService businessExecutePool; //业务线程池
static {
// DEFAULT_NIO_THREAD_COUNT = Runtime.getRuntime().availableProcessors() > 1
// ? 2 * (Runtime.getRuntime().availableProcessors() - 1 ) : 2;
DEFAULT_NIO_THREAD_COUNT = 4;
}
public SubReactorThreadGroup() {
this(DEFAULT_NIO_THREAD_COUNT);
}
public SubReactorThreadGroup(int threadCount) {
写在最后
学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!
最后再分享的一些BATJ等大厂20、21年的面试题,把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。
[外链图片转存中…(img-YGnCAZXZ-1713424132354)]
Mybatis面试专题
[外链图片转存中…(img-mPA0xXUj-1713424132355)]
MySQL面试专题
[外链图片转存中…(img-fOeUsVjE-1713424132355)]
并发编程面试专题
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-b8NfSq4R-1713424132355)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!