动态代理与静态代理最大的不同在于,动态代理中,代理类对象由JVM生成,不再需要我们自己编写代理类。
核心实现:
1. java.lang.reflect.Proxy类动态生成代理类和对象,它提供用于创建动态代理类和实例的静态方法,是由这些方法创建的所有动态代理类的超类。
2.java.lang.reflect.InvocationHandler处理器接口,可以通过invoke方法实现对真实角色的访问。(每次通过Proxy生成代理类对象时都要指定该处理器接口) (更多…)
装饰模式的核心实现:
1.抽象组件(Component):具体类和装饰类基本功能规范,通过二者的实现,可以通过多态方式互为引用。
2.具体组件(Concrete Component):抽象组件的具体实现类。
3.抽象装饰(Decorator):继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
4.具体装饰(ConcreteDecorator):实现抽象装饰的相关方法,并给具体构件对象添加附加的功能。
下面以实例说明实现过程: (更多…)
一. java线程组特点:
1.所有用户创建的线程默认属于main线程组。main线程组是JVM在应用程序运行时自动创建。
2.如果线程A创建了线程B,创建时未指定线程组,那么线程组B自动加入线程A所在线程组。
3.线程一旦加入某个线程组,该线程就一直留着该组中,直至线程死亡,中途不可改变所属线程组。
4.用户创建的线程组默认都有一个父线程组。如线程A创建了线程组X,那么线程A所在线程组则默认称为线程组X的父线程组。
通过以下示例可验证:
package net.mosang.threadgroup; /** * 线程类 * @author Heiry * 模拟登录 */ public class SignUp implements Runnable{ private String userName; private String passWord; public SignUp(String userName, String passWord) { this.userName = userName; this.passWord = passWord; } @Override public void run() { System.out.println("你登录的用户名是:"+userName+"密码是:"+passWord); if(userName.equals("创建线程组")) { ThreadGroup tg = new ThreadGroup("newTg"); System.out.println("新线程内创建的线程组名是:"+tg.getName()); System.out.println("新线程内创建的线程组父线程组名是:"+tg.getParent().getName()); } } }
package net.mosang.threadgroup; /** * 线程组示例 * @author Heiry * */ public class ThreadGroupDemo { public static void main(String[] args) { SignUp u1 = new SignUp("heiry", "123"); SignUp u2 = new SignUp("mosang", "456"); Thread tu1 = new Thread(u1);//创建线程 Thread tu2 = new Thread(u2);//创建线程 System.out.println(tu1.getThreadGroup().getName());//输出“main”,tu1所属线程组 System.out.println(tu2.getThreadGroup().getName());//输出“main”, tu2所属线程组 ThreadGroup g1 = new ThreadGroup("用户线程组A");//创建线组,不指定父线程组 ThreadGroup g2 = new ThreadGroup("用户线程组B");//创建线组,不指定父线程组 Thread tu3 = new Thread(g1,u1);//创建线程,指定线程组 Thread tu4 = new Thread(g2,u2);//创建线程,指定线程组 System.out.println(tu3.getThreadGroup().getName());//输出“用户线程组A”,tu3所属线程组 System.out.println(tu4.getThreadGroup().getName());//输出“用户线程组B”, tu4所属线程组 System.out.println("g1父线程组是--->"+g1.getParent().getName()); // 输出“main” System.out.println("g2父线程组是--->"+g2.getParent().getName()); // 输出“main” SignUp u3 = new SignUp("创建线程组", "789");//线程内将创建线程组 Thread tu5 = new Thread(g1,u3);//创建线程,指定线程组 tu5.start(); } }
输出结果:
main main 用户线程组A 用户线程组B g1父线程组是--->main g2父线程组是--->main 你登录的用户名是:创建线程组密码是:789 新线程内创建的线程组名是:newTg 新线程内创建的线程组父线程组名是:用户线程组A
Callable 接口与Runnable接口类似可实现多线程的创建,但与Runnable不同的是,其线程方法call()有返回值并可抛出异常(Runnable 不会返回结果,并且无法抛出经过检查的异常)。另外Callable创建多线程依赖于线程池。
通过API查询,可以看到,Callable<V>是带泛型的,其泛型就是call方法返回值类型。
以下通过创建商品“秒杀”多线程FlashSale,实例讲解Callable 实现多线程的步骤:
1. 创建线程类FlashSale,实现Callable接口,重写call方法。
2.创建FlashSale线程实例binge,craze。
3.创建线程池对象实例shoppingPool
4.通过线程池实例shoppingPool的submit方法执行binge,craze。
package net.mosang.callabledemo; import java.util.concurrent.Callable; /** * FlashSale线程类 * @author Heiry * 重写不带任何参数的 call方法,返回String类型的抢购结果提示 */ public class FlashSale implements Callable<String>{ private String goodsName; @Override public String call() throws Exception { if(goodsName.equals("Mac电脑")) { return "抢到了苹果电脑"; }else if (goodsName.equals("Mi手机")) { return "抢到了小米手机"; } else { return "什么也没抢到"; } } public FlashSale(String goodsName) { super(); this.goodsName = goodsName; } }
package net.mosang.callabledemo; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * * @author Heiry * */ public class Shopping { public static void main(String[] args) throws InterruptedException, ExecutionException { FlashSale binge = new FlashSale("Mac电脑"); //创建线程实例binge FlashSale craze = new FlashSale("Mi手机");//创建线程实例craze ExecutorService shoppingPool = Executors.newFixedThreadPool(2); Future<String> s1 = shoppingPool.submit(binge); Future<String> s2 = shoppingPool.submit(craze); System.out.println(s1.get()); System.out.println(s2.get()); } }
输出结果
抢到了苹果电脑 抢到了小米手机
可见,相比继承Thread与实现Runable接口方式实现多线程,Callable更方便地得到多线程的返回值并进行异常处理。另外,Callable依赖于线程池,通过此方式创建多线程,步骤繁琐,更适合处理高并发。
适配器模式包含以下主要角色。
1. 已经存在的、具备完备功能的类 Adaptee(适配者)。
2. 当前系统业务所期待的接口(Target),但与现Adaptee不兼容,它可以是抽象类或接口。
3. 适配器类(Adapter)。通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
实例:
现有一个两孔插座,能对外提供220v稳定电压,但现业务需要,需要提供三孔插座,同样输出220v稳定电压,这就需要一个适配器来进行转换。
代码结构及详细:
package net.mosang.adapter; public interface ThreeSocket { public void threeSocket220v();//期望三孔输出220v电压的插线板 }
package net.mosang.adapter; public class TwoSocket { public void twoSocket220v() {//现有两孔可输出220v电压的插线板 System.out.println("220v电压持续输出中。。。。。"); } }
package net.mosang.adapter; public class Adaptor implements ThreeSocket { private TwoSocket two; @Override public void threeSocket220v() { //对外提供了三孔220v电压功能线板 two.twoSocket220v();//实际依然是经过两孔输出 } public TwoSocket getTwo() { return two; } public void setTwo(TwoSocket two) { this.two = two; } public Adaptor(TwoSocket two) { super(); this.two = two; } }
package net.mosang.adapter; public class Client { public static void main(String[] args) { TwoSocket two = new TwoSocket(); Adaptor adaptor = new Adaptor(two); adaptor.threeSocket220v(); // 输出"220v电压持续输出中。。。。。" } }
UML关系图: