diff --git a/README.md b/README.md index e36cb60..54b40bb 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,8 @@ - [CAS](https://github.com/lihengming/java-codes/tree/master/concurrent/src/main/java/cas) - [Unsafe](https://github.com/lihengming/java-codes/tree/master/concurrent/src/main/java/unsafe) - [生产者 - 消费者模型](https://github.com/lihengming/java-codes/tree/master/concurrent/src/main/java/pcmodel) - +- [网络](https://github.com/lihengming/java-codes/tree/master/socket) + - [一个类实现RPC框架](https://github.com/lihengming/java-codes/tree/master/socket/src/main/java/rpc) - [设计模式](https://github.com/lihengming/java-codes/tree/master/design-pattern) - [创建型模式(Creational)](https://github.com/lihengming/java-codes/tree/master/design-pattern/src/main/java/creational) - [简单工厂模式(Simple Factory)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/creational/SimpleFactoryPattern.java) @@ -30,7 +31,7 @@ - [适配器模式(Adapter)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/structural/AdapterPattern.java) - [代理模式(Proxy)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/structural/ProxyPattern.java) - [装饰模式(Decorator)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/structural/DecoratorPattern.java) - - 桥接模式(Bridge) + - [桥接模式(Bridge)](https://github.com/lihengming/java-codes/blob/master/design-pattern/src/main/java/structural/BridgePattern.java) - 组合模式(Composite) - 享元模式(Flyweight) - [行为型模式(Behavioral)](https://github.com/lihengming/java-codes/tree/master/design-pattern/src/main/java/behavioral) diff --git a/concurrent/src/main/java/juc/CountDownLatchTest.java b/concurrent/src/main/java/juc/CountDownLatchTest.java index 8c30e98..7bed6bd 100644 --- a/concurrent/src/main/java/juc/CountDownLatchTest.java +++ b/concurrent/src/main/java/juc/CountDownLatchTest.java @@ -6,7 +6,7 @@ * Created by 李恒名 on 2017/6/18. */ public class CountDownLatchTest { - static CountDownLatch latch = new CountDownLatch(3);//创建计数器并设置初始值为 + static CountDownLatch latch = new CountDownLatch(3);//创建计数器并设置初始值为3 static void work() { System.out.println(Thread.currentThread().getName() + " Work End"); diff --git a/concurrent/src/main/java/juc/SemaphoreTest.java b/concurrent/src/main/java/juc/SemaphoreTest.java index a5080f5..0ab226c 100644 --- a/concurrent/src/main/java/juc/SemaphoreTest.java +++ b/concurrent/src/main/java/juc/SemaphoreTest.java @@ -41,10 +41,11 @@ public void use() { System.out.println(Thread.currentThread().getName() +" 正在使用卫生间"); TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName() +" 使用完毕"); - //释放许可 - semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); + } finally{ + //释放许可 + semaphore.release(); } } } diff --git a/concurrent/src/main/java/thread/DeadlockTest.java b/concurrent/src/main/java/thread/DeadlockTest.java new file mode 100644 index 0000000..88e90ef --- /dev/null +++ b/concurrent/src/main/java/thread/DeadlockTest.java @@ -0,0 +1,57 @@ +package thread; + +import java.util.concurrent.TimeUnit; + +/** + * Created by 李恒名 on 2017/8/29. + * + * 死锁测试,线程1获得A锁(monitor)之后尝试获得B锁,线程2获得B锁后尝试获得A锁,线程1和线程2即产生死锁。 + */ +public class DeadlockTest { + public static void main(String[] args) { + Object lockA = new Object(); + Object lockB = new Object(); + new Thread(() -> { + //线程1获得A锁 + synchronized (lockA){ + System.out.println("Thread 1 get lock A ."); + //增加死锁发生几率 + try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {} + //尝试获得B锁 + System.out.println("Thread 1 try get lock B, waiting..."); + synchronized (lockB){ + //永远无法获得B锁,所以不会打印出来 + System.out.println("Thread 1 get lock B ."); + } + + } + }, "Thread 1").start(); + new Thread(() -> { + //线程2获得B锁 + synchronized (lockB){ + System.out.println("Thread 2 get lock B ."); + //增加死锁发生几率 + try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {} + //尝试获得A锁 + System.out.println("Thread 2 try get lock A, waiting..."); + synchronized (lockA){ + //永远无法获得A锁,所以不会打印出来 + System.out.println("Thread 2 get lock A ."); + } + + } + }, "Thread 2").start(); + + /** + > jstack [pid] + + "Thread 2": + waiting to lock monitor 0x0000000002cc7338 (object 0x000000076b7b31d8, a java.lang.Object), + which is held by "Thread 1" + "Thread 1": + waiting to lock monitor 0x0000000002cc9bc8 (object 0x000000076b7b31e8, a java.lang.Object), + which is held by "Thread 2" + + */ + } +} diff --git a/data-structure-algorithm/src/main/java/data/structure/queue/QueueLinkedImpl.java b/data-structure-algorithm/src/main/java/data/structure/queue/QueueLinkedImpl.java index abefe8b..c0c8e9c 100644 --- a/data-structure-algorithm/src/main/java/data/structure/queue/QueueLinkedImpl.java +++ b/data-structure-algorithm/src/main/java/data/structure/queue/QueueLinkedImpl.java @@ -22,7 +22,8 @@ public void enQueue(Object element) { if (first == null) { first = last; } else { - oldLast.element = last; + //2017年7月26日17:28:33 原始链表尾的next指针指向新加的节点 + oldLast.next = last; } } diff --git a/design-pattern/src/main/java/structural/BridgePattern.java b/design-pattern/src/main/java/structural/BridgePattern.java new file mode 100644 index 0000000..510baf9 --- /dev/null +++ b/design-pattern/src/main/java/structural/BridgePattern.java @@ -0,0 +1,97 @@ +package structural; + +/** + * Created by 李恒名 on 2017/10/06. + * + * 桥接模式的意图是将抽象类与抽象方法的实现相互分离来实现解耦,以便二者可以相互独立地变化。 + * + * 比如太阳镜,太阳镜有很多种品牌,不管何种品牌它们都会提供不同的风格供顾客选择,比如复古 + * 风格、飞行员风格等,太阳镜与风格间的关系便可使用该模式来维护。 + */ +public class BridgePattern { + //太阳镜的抽象类 + static abstract class SunGlasses { + protected Style style; + + protected SunGlasses(Style style) { + this.style = style; + } + + //获取品牌名称 + abstract String getBrandName(); + + //戴眼镜 + public void putOn() { + System.out.println("戴上" + getBrandName() + "-" + style.getStyle() + "风格的太阳镜"); + } + } + + static class BolonSunGlasses extends SunGlasses { + public BolonSunGlasses(Style style) { + super(style); + } + + @Override + String getBrandName() { + return "暴龙"; + } + } + + static class DiorSunGlasses extends SunGlasses { + public DiorSunGlasses(Style style) { + super(style); + } + + @Override + String getBrandName() { + return "迪奥"; + } + } + + //太阳镜风格接口 + interface Style { + String getStyle(); + } + + //复古风格 + static class RetroStyle implements Style { + + @Override + public String getStyle() { + return "复古"; + } + } + + //飞行员风格 + static class PilotStyle implements Style { + + @Override + public String getStyle() { + return "飞行员"; + } + } + + public static void main(String[] args) { + RetroStyle retroStyle = new RetroStyle(); + PilotStyle pilotStyle = new PilotStyle(); + + SunGlasses glasses = new DiorSunGlasses(retroStyle); + glasses.putOn(); + //戴上迪奥-复古风格的太阳镜 + glasses = new DiorSunGlasses(pilotStyle); + glasses.putOn(); + //戴上迪奥-飞行员风格的太阳镜 + glasses = new BolonSunGlasses(pilotStyle); + glasses.putOn(); + //戴上暴龙-飞行员风格的太阳镜 + } + + /** + * 总结: + * 如果说某个系统能够从多个角度来进行分类,且每一种分类都可能会变化,那么我们需要做 + * 的就是讲这多个角度分离出来,使得他们能独立变化,减少他们之间的耦合,这个分离过 + * 程就使用了桥接模式。所谓桥接模式就是讲抽象部分和实现部分隔离开来,使得他们能够 + * 独立变化。桥接模式将继承关系转化成关联关系,封装了变化,完成了解耦,减少了系统 + * 中类的数量,也减少了代码量。 + */ +} diff --git a/design-pattern/src/main/java/structural/ProxyPattern.java b/design-pattern/src/main/java/structural/ProxyPattern.java index 5af35d7..6079a82 100644 --- a/design-pattern/src/main/java/structural/ProxyPattern.java +++ b/design-pattern/src/main/java/structural/ProxyPattern.java @@ -59,32 +59,31 @@ public static void main(String[] args) { // 如果,代理目标方法较多使用静态代理较为麻烦,可以使用动态代理,下面是使用JDK实 // 现动态代理的方式,这种方式有一个要求,被代理的对象必须实现接口。 - List list = (List) new DynamicProxy() - .proxy(new ArrayList()); + List list = DynamicProxy.proxy(new ArrayList()); list.add("data"); + list.size(); list.remove("data"); - list.clear(); /** - * 前置代理,调用方法:add + * 前置代理,调用方法:add() * 后置代理,方法返回:true - * 前置代理,调用方法:remove + * 前置代理,调用方法:size() + * 后置代理,方法返回:1 + * 前置代理,调用方法:remove() * 后置代理,方法返回:true - * 前置代理,调用方法:clear - * 后置代理,方法返回:null */ // 当然除了JDK 提供的方式外我们也可以使用 CGLIB 来使用动态代理,它不要求代理的对象 // 必须实现接口,这基于ASM 字节码技术。 } - static class DynamicProxy { + private static class DynamicProxy { - public T proxy(T target) { + public static T proxy(T target) { return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), (proxy, method, args) -> { - System.out.println("前置代理,调用方法:" + method.getName()); + System.out.println("前置代理,调用方法:" + method.getName()+"()"); Object result = method.invoke(target, args); System.out.println("后置代理,方法返回:" + result); return result; diff --git a/jvm/src/main/java/classloader/CustomClassLoader.java b/jvm/src/main/java/classloader/CustomClassLoader.java index eb22706..b9a0069 100644 --- a/jvm/src/main/java/classloader/CustomClassLoader.java +++ b/jvm/src/main/java/classloader/CustomClassLoader.java @@ -11,11 +11,6 @@ public class CustomClassLoader extends ClassLoader { private final String classesDir; - @Override - public Class loadClass(String name) throws ClassNotFoundException { - return super.loadClass(name,true); - } - public CustomClassLoader(String classesDir) { this.classesDir = classesDir; } @@ -23,11 +18,10 @@ public CustomClassLoader(String classesDir) { @Override protected Class findClass(String name) throws ClassNotFoundException { String fileName = name; - if (fileName.indexOf('.') > 0) { - fileName.replaceAll(".", "\\"); + if (fileName.indexOf('.') != -1) { + fileName = fileName.replaceAll("\\.", "\\\\"); } fileName = fileName + ".class"; - try { try (FileInputStream in = new FileInputStream(classesDir + fileName)) { try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { @@ -40,11 +34,9 @@ protected Class findClass(String name) throws ClassNotFoundException { return defineClass(name, data, 0, data.length); } } - } catch (IOException e) { - e.printStackTrace(); + throw new ClassNotFoundException(name); } - return super.findClass(name); } public static void main(String[] args) throws ReflectiveOperationException{ diff --git "a/shared-resources/\351\230\277\351\207\214\345\267\264\345\267\264Java\345\274\200\345\217\221\346\211\213\345\206\214V1.3.0.pdf" "b/shared-resources/\351\230\277\351\207\214\345\267\264\345\267\264Java\345\274\200\345\217\221\346\211\213\345\206\214V1.3.0.pdf" new file mode 100644 index 0000000..e6ed0c5 Binary files /dev/null and "b/shared-resources/\351\230\277\351\207\214\345\267\264\345\267\264Java\345\274\200\345\217\221\346\211\213\345\206\214V1.3.0.pdf" differ diff --git a/socket/pom.xml b/socket/pom.xml index 62e99a9..5a9cf57 100644 --- a/socket/pom.xml +++ b/socket/pom.xml @@ -10,6 +10,12 @@ 4.0.0 socket - - + + + + io.netty + netty + 3.5.2.Final + + \ No newline at end of file diff --git a/socket/src/main/java/netty/HelloClient.java b/socket/src/main/java/netty/HelloClient.java new file mode 100644 index 0000000..b722900 --- /dev/null +++ b/socket/src/main/java/netty/HelloClient.java @@ -0,0 +1,41 @@ +package netty; + +import org.jboss.netty.bootstrap.ClientBootstrap; +import org.jboss.netty.channel.*; +import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; + +import java.net.InetSocketAddress; +import java.util.concurrent.Executors; + +/** + * Created by 李恒名 on 2017/8/8. + */ +public class HelloClient { + public static void main(String args[]) { + // Client服务启动器 + ClientBootstrap bootstrap = new ClientBootstrap( + new NioClientSocketChannelFactory( + Executors.newCachedThreadPool(), + Executors.newCachedThreadPool())); + // 设置一个处理服务端消息和各种消息事件的类(Handler) + bootstrap.setPipelineFactory(() -> Channels.pipeline(new HelloClientHandler())); + // 连接到本地的8000端口的服务端 + bootstrap.connect(new InetSocketAddress("127.0.0.1", 8000)); + } + + private static class HelloClientHandler extends SimpleChannelHandler { + + + /** + * 当绑定到服务端的时候触发,打印"Hello world, I am client." + * + * @alia OneCoder + * @author lihzh + */ + @Override + public void channelConnected(ChannelHandlerContext ctx, + ChannelStateEvent e) { + System.out.println("Hello world, I am client."); + } + } +} diff --git a/socket/src/main/java/netty/NettyTest.java b/socket/src/main/java/netty/NettyTest.java new file mode 100644 index 0000000..f48e423 --- /dev/null +++ b/socket/src/main/java/netty/NettyTest.java @@ -0,0 +1,51 @@ +package netty; + + +import org.jboss.netty.bootstrap.ServerBootstrap; +import org.jboss.netty.channel.*; +import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; + +import java.net.InetSocketAddress; +import java.util.concurrent.Executors; + +/** + * Created by 李恒名 on 2017/8/8. + */ +public class NettyTest { + public static void main(String[] args) { + // Server服务启动器 + ServerBootstrap bootstrap = new ServerBootstrap( + new NioServerSocketChannelFactory( + Executors.newCachedThreadPool(), + Executors.newCachedThreadPool())); + // 设置一个处理客户端消息和各种消息事件的类(Handler) + bootstrap + .setPipelineFactory(new ChannelPipelineFactory() { + @Override + public ChannelPipeline getPipeline() + throws Exception { + return Channels + .pipeline(new HelloServerHandler()); + } + }); + // 开放8000端口供客户端访问。 + bootstrap.bind(new InetSocketAddress(8000)); + } + + private static class HelloServerHandler extends + SimpleChannelHandler { + + /** + * 当有客户端绑定到服务端的时候触发,打印"Hello world, I am server." + * + * @alia OneCoder + * @author lihzh + */ + @Override + public void channelConnected( + ChannelHandlerContext ctx, + ChannelStateEvent e) { + System.out.println("Hello world, I am server."); + } + } +} diff --git a/socket/src/main/java/rpc/RpcTest.java b/socket/src/main/java/rpc/RpcTest.java new file mode 100644 index 0000000..ef46e0a --- /dev/null +++ b/socket/src/main/java/rpc/RpcTest.java @@ -0,0 +1,60 @@ +package rpc; + +import java.util.concurrent.TimeUnit; + +import static rpc.SimpleRpcFramework.export; +import static rpc.SimpleRpcFramework.use; + +/** + * Created by 李恒名 on 2017/8/17. + */ +public class RpcTest { + private static final String HOST = "localhost"; + private static final int PORT = 8888; + + interface ComputeService { + int sum(int a, int b); + } + + + static class ComputeServiceImpl implements ComputeService { + + @Override + public int sum(int a, int b) { + return a + b; + } + } + + //服务提供者 + static class Provider implements Runnable { + @Override + public void run() { + //暴露服务 + export(new ComputeServiceImpl(), PORT); + } + } + + //服务消费者 + static class Customer implements Runnable { + @Override + public void run() { + //使用服务 + ComputeService computeService = use(ComputeService.class, HOST, PORT); + for (int i = 0; i < 10; i++) { + int sum = computeService.sum(1, 1); + System.out.println("SUM:" + sum); + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + public static void main(String[] args) { + new Thread(new Provider()).start(); + new Thread(new Customer()).start(); + new Thread(new Customer()).start(); + } +} diff --git a/socket/src/main/java/rpc/SimpleRpcFramework.java b/socket/src/main/java/rpc/SimpleRpcFramework.java new file mode 100644 index 0000000..dd90d16 --- /dev/null +++ b/socket/src/main/java/rpc/SimpleRpcFramework.java @@ -0,0 +1,67 @@ +package rpc; + +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.ServerSocket; +import java.net.Socket; + +/** + * Created by 李恒名 on 2017/8/17. + */ +public class SimpleRpcFramework { + + /** + * 暴漏服务 + * @param serviceImpl 服务的实现 + * @param port 服务所处的端口号 + */ + public static void export(Object serviceImpl, int port) { + try { + try (ServerSocket server = new ServerSocket(port)) { + while (!Thread.currentThread().isInterrupted()) { + Socket socket = server.accept(); + new Thread(() -> { + try (ObjectInputStream in = new ObjectInputStream(socket.getInputStream())) { + Method method = serviceImpl.getClass().getMethod(in.readUTF(), (Class[]) in.readObject()); + Object result = method.invoke(serviceImpl, (Object[]) in.readObject()); + try (ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream())) { + out.writeObject(result); + } + System.out.println("Invoke method [" + method.getName() + "()] success, form " + socket.getRemoteSocketAddress()); + } catch (Exception e) { + throw new RuntimeException("Export service fail .", e); + } + }).start(); + } + } + } catch (Exception e) { + throw new RuntimeException("Export service fail .", e); + } + System.out.println("Export service " + serviceImpl.getClass().getSimpleName() + " success on port " + port); + } + + /** + * 使用服务 + * @param serviceInterface 要使用的服务的接口 + * @param host 服务所处的主机名称 + * @param port 服务所处的端口号 + * @return 服务 + */ + public static T use(Class serviceInterface, String host, int port) { + System.out.println(String.format("Use remote service [%s] from [%s:%s]", serviceInterface.getSimpleName(), host, port)); + return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class[]{serviceInterface}, (proxy, method, args) -> { + try (Socket socket = new Socket(host, port)) { + try (ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream())) { + out.writeUTF(method.getName()); + out.writeObject(method.getParameterTypes()); + out.writeObject(args); + try (ObjectInputStream in = new ObjectInputStream(socket.getInputStream())) { + return in.readObject(); + } + } + } + }); + } +}