java借助NIO、链表、跳表模拟实现redis
LinkItem.java:链表的一个元素
package com.qixian.general.entity;public class LinkItem {public String key;public long keyascii=0;public void getAsciiCode() {String keyasciiStr="";for(int i=0;i<key.length();i++){keyasciiStr=keyasciiStr+(int)key.charAt(i);}keyascii = Long.parseLong(keyasciiStr);}public LinkItem previous;public LinkItem next;public Object data;
}
LinkSkip.java :跳表的上部类似索引的部分
package com.qixian.general.entity;public class LinkSkip {public String key;public long keyascii=0;public LinkSkip previous;public LinkSkip next;public LinkItem current;public LinkSkip currentSkip;
}
MyHashMap.java:自己用java模拟的哈希结构,数据存储为跳表结构
package com.qixian.general.study;public class MyHashMap {int[] index={0,1,2,3,4,5,6,7,8,9};SkipList skipList0=new SkipList();SkipList skipList1=new SkipList();SkipList skipList2=new SkipList();SkipList skipList3=new SkipList();SkipList skipList4=new SkipList();SkipList skipList5=new SkipList();SkipList skipList6=new SkipList();SkipList skipList7=new SkipList();SkipList skipList8=new SkipList();SkipList skipList9=new SkipList();public Object get(String key){String keyasciiStr="";for(int i=0;i<key.length();i++){keyasciiStr=keyasciiStr+(int)key.charAt(i);}long keyascii = Long.parseLong(keyasciiStr);long index =dividekey(keyascii);Object data = null;switch ((int) index){case 0:data=skipList0.getData(key);break;case 1:data=skipList1.getData(key);break;case 2:data=skipList2.getData(key);break;case 3:data=skipList3.getData(key);break;case 4:data=skipList4.getData(key);break;case 5:data=skipList5.getData(key);break;case 6:data=skipList6.getData(key);break;case 7:data=skipList7.getData(key);break;case 8:data=skipList8.getData(key);break;case 9:data=skipList9.getData(key);break;default:break;}return data;}public void put(String key,Object value){String keyasciiStr="";for(int i=0;i<key.length();i++){keyasciiStr=keyasciiStr+(int)key.charAt(i);}long keyascii = Long.parseLong(keyasciiStr);long index =dividekey(keyascii);switch ((int) index){case 0:skipList0.addLinkItem(key,value);break;case 1:skipList1.addLinkItem(key,value);break;case 2:skipList2.addLinkItem(key,value);break;case 3:skipList3.addLinkItem(key,value);break;case 4:skipList4.addLinkItem(key,value);break;case 5:skipList5.addLinkItem(key,value);break;case 6:skipList6.addLinkItem(key,value);break;case 7:skipList7.addLinkItem(key,value);break;case 8:skipList8.addLinkItem(key,value);break;case 9:skipList9.addLinkItem(key,value);break;default:break;}}long dividekey(long keyascii){keyascii=keyascii/2;if(keyascii>9){return dividekey(keyascii);}else {return keyascii;}}public static void main(String[] args) {SkipList list=new SkipList();list.addLinkItem("qiang","{name:wlq,sex:男}");list.addLinkItem("qiang2","{name:wlq2,sex:男}");list.addLinkItem("qiang3","{name:wlq3,sex:男}");list.addLinkItem("qiang4","{name:wlq4,sex:男}");list.addLinkItem("qiang5","{name:wlq5,sex:男}");list.addLinkItem("qiang6","{name:wlq6,sex:男}");list.addLinkItem("qiang7","{name:wlq7,sex:男}");list.addLinkItem("qiang8","{name:wlq8,sex:男}");list.addLinkItem("qiang9","{name:wlq9,sex:男}");list.addLinkItem("qiang10","{name:wlq10,sex:男}");list.addLinkItem("qiang11","{name:wlq11,sex:男}");list.addLinkItem("qiang12","{name:wlq12,sex:男}");list.addLinkItem("qiang13","{name:wlq13,sex:男}");list.addLinkItem("qiang14","{name:wlq14,sex:男}");list.addLinkItem("qiang15","{name:wlq15,sex:男}");list.addLinkItem("qiang16","{name:wlq16,sex:男}");Object qiang3 = list.getData("qiang10");System.out.println(qiang3.toString());}
}
SkipList.java :一个跳表类型
package com.qixian.general.study;import com.qixian.general.entity.LinkItem;
import com.qixian.general.entity.LinkSkip;public class SkipList {public LinkItem firstLinkItem;public LinkSkip rootSkipItem;public Object getData(String key){long keyascii=0;String keyasciiStr="";for(int i=0;i<key.length();i++){keyasciiStr=keyasciiStr+(int)key.charAt(i);}keyascii = Long.parseLong(keyasciiStr);Boolean advance=true;LinkSkip root=rootSkipItem;LinkItem target;while (true){if(advance){if(root.keyascii<keyascii){if(root.next!=null){root=root.next;}else {root=root.currentSkip;}}else {if(root.currentSkip==null){target=root.current;advance=false;break;}else {root=root.currentSkip;advance=false;}}}else {if(root.keyascii>keyascii){if(root.previous!=null){root=root.previous;}else {root=root.currentSkip;}}else {if(root.currentSkip==null){target=root.current;advance=true;break;}else {root=root.currentSkip;advance=true;}}}}while (true){if(target.keyascii==keyascii){break;}else {if(advance) {target=target.next;}else {target=target.previous;}}}return target.data;}public void generateSkip(){if(firstLinkItem!=null){rootSkipItem=new LinkSkip();rootSkipItem.current=firstLinkItem;rootSkipItem.keyascii=firstLinkItem.keyascii;if(firstLinkItem.next!=null){generate(rootSkipItem,firstLinkItem.next,0);}while (countLinkSkip()>=3){LinkSkip newRootSkipItem=new LinkSkip();newRootSkipItem.currentSkip=rootSkipItem;newRootSkipItem.keyascii=rootSkipItem.keyascii;generateSkipItem(newRootSkipItem,rootSkipItem.next,0);rootSkipItem=newRootSkipItem;}}}public int countLinkSkip(){int count=0;LinkSkip current=rootSkipItem;while (true){count++;if(current.next==null){break;}else {current=current.next;}}return count;}public void generateSkipItem(LinkSkip linkSkipCurrent,LinkSkip linkSkipLowCurrent,int interim){LinkSkip item=null;if(interim==1){item=new LinkSkip();item.keyascii=linkSkipLowCurrent.keyascii;item.currentSkip=linkSkipLowCurrent;}if(item==null){item=linkSkipCurrent;}else {linkSkipCurrent.next=item;item.previous=linkSkipCurrent;}interim=interim==0?1:0;if(linkSkipLowCurrent.next!=null){generateSkipItem(item,linkSkipLowCurrent.next,interim);}}public void generate(LinkSkip linkSkipCurrent,LinkItem linkItemCurrent,int interim){LinkSkip item=null;if(interim==1){item=new LinkSkip();item.keyascii=linkItemCurrent.keyascii;item.current=linkItemCurrent;}if(item==null){item=linkSkipCurrent;}else {linkSkipCurrent.next=item;item.previous=linkSkipCurrent;}interim=interim==0?1:0;if(linkItemCurrent.next!=null){generate(item,linkItemCurrent.next,interim);}}public void addLinkItem(String key,Object data){LinkItem linkItem=new LinkItem();linkItem.key=key;linkItem.data=data;linkItem.getAsciiCode();if(firstLinkItem==null){firstLinkItem=linkItem;}else {addLinkItem(firstLinkItem,linkItem);}generateSkip();}private void addLinkItem(LinkItem linkItemCurrent,LinkItem linkItem){if(linkItemCurrent.keyascii<linkItem.keyascii){if(linkItemCurrent.next!=null){addLinkItem(linkItemCurrent.next,linkItem);}else {linkItemCurrent.next=linkItem;}}else {if(linkItemCurrent.previous!=null){linkItemCurrent.previous.next=linkItem;linkItem.previous=linkItemCurrent.previous;}linkItem.next=linkItemCurrent;linkItemCurrent.previous=linkItem;}}}
MyRedis.java:借助NIO实现单线程可以并发响应网络连接请求,并单线程操作hash表存放和查询数据,此处的hash是redis全局大hash,key值唯一,数据类型可以是字符串,链表(队列,栈)等
package com.qixian.general.study;import com.qixian.general.entity.LinkItem;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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;public class MyRedis {public static int[] index={0,1,2,3,4,5,6,7,8,9};static LinkItem myRedisHashMap0=null;static LinkItem myRedisHashMap1=null;static LinkItem myRedisHashMap2=null;static LinkItem myRedisHashMap3=null;static LinkItem myRedisHashMap4=null;static LinkItem myRedisHashMap5=null;static LinkItem myRedisHashMap6=null;static LinkItem myRedisHashMap7=null;static LinkItem myRedisHashMap8=null;static LinkItem myRedisHashMap9=null;public static void main(String[] args) throws IOException, InterruptedException {ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.socket().bind(new InetSocketAddress(8899));serverSocketChannel.configureBlocking(false);Selector selector = Selector.open();SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {selector.select();Set<SelectionKey> selectionKeySet = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeySet.iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();if (key.isAcceptable()) {ServerSocketChannel server = (ServerSocketChannel) key.channel();SocketChannel socketChannel = server.accept();socketChannel.configureBlocking(false);SelectionKey selKey = socketChannel.register(selector, SelectionKey.OP_READ);} else if (key.isReadable()) {SocketChannel socketChannel = (SocketChannel) key.channel();ByteBuffer byteBuffer = ByteBuffer.allocate(128);int len = socketChannel.read(byteBuffer);if (len > 0) {Date date = new Date();SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd :hh:mm:ss");System.out.println(dateFormat.format(date) + "收到了来自于客户端" +socketChannel.socket().getInetAddress().getHostName()+ "的消息:" + new String(byteBuffer.array()));String content= new String(byteBuffer.array());String[] split = content.split(" ");if(split[0].equals("SET")){String key1=split[1];String value1=split[2];String keyasciiStr="";for(int i=0;i<key1.length();i++){keyasciiStr=keyasciiStr+(int)key1.charAt(i);}long keyascii = Long.parseLong(keyasciiStr);long index =dividekey(keyascii);LinkItem linkItem = new LinkItem();linkItem.key=key1;linkItem.keyascii=keyascii;value1=value1.replace("\0","");linkItem.data=value1;switch ((int) index){case 0:myRedisHashMap0=addLinkItem(linkItem,myRedisHashMap0);break;case 1:myRedisHashMap1=addLinkItem(linkItem,myRedisHashMap1);break;case 2:myRedisHashMap2=addLinkItem(linkItem,myRedisHashMap2);break;case 3:myRedisHashMap3=addLinkItem(linkItem,myRedisHashMap3);break;case 4:myRedisHashMap4=addLinkItem(linkItem,myRedisHashMap4);break;case 5:myRedisHashMap5=addLinkItem(linkItem,myRedisHashMap5);break;case 6:myRedisHashMap6=addLinkItem(linkItem,myRedisHashMap6);break;case 7:myRedisHashMap7=addLinkItem(linkItem,myRedisHashMap7);break;case 8:myRedisHashMap8=addLinkItem(linkItem,myRedisHashMap8);break;case 9:myRedisHashMap9=addLinkItem(linkItem,myRedisHashMap9);break;default:break;}}if(split[0].equals("GET")){String key1=split[1];key1=key1.replace("\0","");String keyasciiStr="";for(int i=0;i<key1.length();i++){keyasciiStr=keyasciiStr+(int)key1.charAt(i);}long keyascii = Long.parseLong(keyasciiStr);long index =dividekey(keyascii);LinkItem result=null;LinkItem current=null;switch ((int) index){case 0:result =getListItem(keyascii,myRedisHashMap0);break;case 1:result =getListItem(keyascii,myRedisHashMap1);break;case 2:result =getListItem(keyascii,myRedisHashMap2);break;case 3:result =getListItem(keyascii,myRedisHashMap3);break;case 4:result =getListItem(keyascii,myRedisHashMap4);break;case 5:result =getListItem(keyascii,myRedisHashMap5);break;case 6:result =getListItem(keyascii,myRedisHashMap6);break;case 7:result =getListItem(keyascii,myRedisHashMap7);break;case 8:result =getListItem(keyascii,myRedisHashMap8);break;case 9:result =getListItem(keyascii,myRedisHashMap9);break;default:break;}if(result!=null){System.out.println("查询数据:"+result.data.toString());ByteBuffer wrap = ByteBuffer.wrap(result.data.toString().getBytes(StandardCharsets.UTF_8));socketChannel.write(wrap);}}} else if (len == -1) {socketChannel.close();System.out.println("客户端断开");}}iterator.remove();}}}static LinkItem getListItem(long keyascii,LinkItem current){while (true){if(current.keyascii==keyascii){return current;}else {if(current.next!=null){current=current.next;}else {return null;}}}}static LinkItem addLinkItem(LinkItem linkItem,LinkItem previous){LinkItem root=null;if(previous==null){root=linkItem;return root;}else {while (true){if(linkItem.keyascii<previous.keyascii){if(previous.previous==null){myRedisHashMap0=linkItem;linkItem.next=previous;}else {linkItem.previous=previous.previous;linkItem.next=previous;previous.previous.next=linkItem;previous.previous=linkItem;}break;}else {if(previous.next==null){previous.next=linkItem;break;}else {previous=previous.next;}}}return previous;}}static long dividekey(long keyascii){keyascii=keyascii/2;if(keyascii>9){return dividekey(keyascii);}else {return keyascii;}}// public static void main(String[] args) {
//
// MyHashMap myHashMap=new MyHashMap();
// myHashMap.put("qiang","{name:wlq,sex:男}");
// myHashMap.put("qiang2","{name:wlq2,sex:男}");
// myHashMap.put("qiang3","{name:wlq3,sex:男}");
// myHashMap.put("qiang4","{name:wlq4,sex:男}");
// myHashMap.put("qiang5","{name:wlq5,sex:男}");
// myHashMap.put("qiang6","{name:wlq6,sex:男}");
// myHashMap.put("qiang7","{name:wlq7,sex:男}");
// myHashMap.put("qiang8","{name:wlq8,sex:男}");
// myHashMap.put("qiang9","{name:wlq9,sex:男}");
// myHashMap.put("qiang10","{name:wlq10,sex:男}");
// myHashMap.put("qiang11","{name:wlq11,sex:男}");
// myHashMap.put("qiang12","{name:wlq12,sex:男}");
// myHashMap.put("qiang13","{name:wlq13,sex:男}");
// myHashMap.put("qiang14","{name:wlq14,sex:男}");
// myHashMap.put("qiang15","{name:wlq15,sex:男}");
// myHashMap.put("qiang16","{name:wlq16,sex:男}");
// Object qiang3 = myHashMap.get("qiang10");
// System.out.println(qiang3.toString());
// }
}
测试类:先发送100个存储命令,在发送一个查询命令
package com.tjcloud.uac.facade;import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;public class Study1 {
// public static void main(String[] args) {
// //socket对象初始化
// Socket socket = null;
//
// //输出流 os对象初始化
// OutputStream os = null;
// try {
//
// //1、创建Socket对象,它的第一个参数需要的是服务端的IP,第二个参数是服务端的端口
// InetAddress inet = InetAddress.getByName("127.0.0.1");
// socket = new Socket(inet,8899);//inet是服务端ip
//
// //2、获取一个输出流,用于写出要发送的数据
// os = socket.getOutputStream();
//
// for (int i = 0;i<100;i++){
//
// //3、写出数据
// os.write(("SET wlq"+i+" {name:wlq"+i+",sex:男}").getBytes());
// os.flush();
// Thread.sleep(500);
// }
//
// } catch (IOException e) {
// e.printStackTrace();
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// } finally {
// //4、释放资源,别忘了哦!!!!
// if(socket!=null){
// try {
// socket.close();//关闭
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// if(os!=null){
// try {
// os.close();//关闭
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// }
// }public static void main(String[] args) {//socket对象初始化Socket socket = null;//输出流 os对象初始化OutputStream os = null;try {//1、创建Socket对象,它的第一个参数需要的是服务端的IP,第二个参数是服务端的端口InetAddress inet = InetAddress.getByName("127.0.0.1");socket = new Socket(inet,8899);//inet是服务端ip//2、获取一个输出流,用于写出要发送的数据os = socket.getOutputStream();os.write(("GET wlq"+15).getBytes());os.flush();Thread.sleep(500);} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {//4、释放资源,别忘了哦!!!!if(socket!=null){try {socket.close();//关闭} catch (IOException e) {e.printStackTrace();}}if(os!=null){try {os.close();//关闭} catch (IOException e) {e.printStackTrace();}}}}
//}