线程2

静态代理和动态代理

代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。

静态代理

代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

优点:

可以在不修改目标对象的前提下扩展目标对象的功能。

缺点:

冗余:由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。

不易维护:一旦接口增加方法,目标对象与代理对象都要进行修改。

    public static void main(String[] args) {
        //UserService userService = new UserServiceImpl;
        UserService userService = new UserServiceImplProxy;
        userService.findName();
    }

    interface UserService{
        public abstract void findName();
    }

    class UserServiceImpl implements UserService{
        @Override
        public void findName(){
            System.out.print("正在查询~~~");
        }
    }
    class UserServiceImplProxy implements UserService{
        private UserServiceImpl userServiceImpl = new UserServiceImpl();
        @Override
        public void findName(){
            System.out.print("我是增强方法~~~~~");
            userServiceImpl.findName();
        }
    }
动态代理

动态代理利用了 JDK API,动态地在内存中构建代理对象,从而实现对目标对象的代理功能。

动态代理又被称为 JDK 代理或接口代理。

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserServiceImplProxy_demo userServiceImplProxy_demo = new UserServiceImplProxy_demo();
        //get(XXX)方法,XXX表示需要代理的对象
        UserService userServiceProxy = (UserService)userServiceImplProxy_demo.get(userService);
        userServiceProxy.findName();
    }

    interface UserService{
        public abstract void findName();
    }

    class UserServiceImpl implements UserService{
        @Override
        public void findName(){
            System.out.print("正在查询~~~");
        }
    }

    class UserServiceImplProxy_demo implements InvocationHandler{

        //写代码的时候不知道需要代理哪个对象
        private Object object;
        //获取原始对象,产生代理对象
        public void get(Object o){
            this.object = o;
            //获取类加载器和接口
            return Proxy.newProxyInstance(this.object.getClass().getClassLoader(),this.object.getClass().geiInterfaces(),this)
        }
        //静态代理产生对象:
        //UserService userService = new UserServiceImplProxy;

        System.out.print("我是增强方法2~~~~~");

        @Override
        public Object invoke(Object Proxy,Method method,Object[] args) throws Throwable{
            /*
                Proxy:对象
                method:代理的对象的方法
                args:参数
            */
            return method.invoke(this.object,args);
        }
    }
静态代理与动态代理的区别主要在:

静态代理在编译时就已经实现,编译完成后代理类是一个实际的 class 文件

动态代理是在运行时动态生成的,即编译完成后没有实际的 class 文件,而是在运行时动态生成类字节码,并加载到 JVM 中

注意:

动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理。

JDK 中生成代理对象主要涉及两个类:

第一个类为 java.lang.reflect.Proxy,通过静态方法 newProxyInstance 生成代理对象,

第二个类为 java.lang.reflect.InvocationHandler 接口,通过 invoke 方法对业务进行增强

线程基本使用:

多线程执行:
例:

编写一个程序,创建两个线程,

一个线程每隔1秒输出”hello world”,输出10次退出;

一个线程每隔1秒输出”hi”,输出5次退出

    public static void main(String[] args) {
        T1 t1 = new T1();
        T2 t2 = new T2();
        Thread thread1 = new Thread(t1);
        Thread thread2 = new Thread(t2);
        thread1.start();    //启动第1个线程
        thread2.start();    //启动第2个线程


    }

    class T1 implements Runnable{
        int count = 0;
        @Override
        public void run(){
            while(true){
                System.out.print("hello world");

                //try-catch
                Thread.sleep(1000);
                //try-catch

                if (count == 10) {
                    break;
                }
            }

        }
    }

    class T2 implements Runnable{
        int count = 0;
        @Override
        public void run(){
            while(true){
                System.out.print("hi~~~~~");

                //try-catch
                Thread.sleep(1000);
                //try-catch

                if (count == 5) {
                    break;
                }
            }
        }
    }       

继承Thread VS 实现Runnable的区别:

  1. 从java的设计来看,通过继承Thread或者实现Runnable接口来创建线程本质上没有区别,从jdk帮助文档我们可以看到Thread类本身就实现了Runnable接口
  2. 实现Runnable接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制
如:
    T3 t3 = new T3("hello");
    //两个线程共享t3
    Thread thread01 = new Thread(t3);
    Thread thread02 = new Thread(t3);
    thread01.start();
    thread02.start();
例:

编程模拟三个售票窗口售票100张;分别使用继承Thread 和 实现Runnable接口 方式

    -------------------------------------------
    public static void main(String[] args) {
        SellTicket01 sellTicket01 = new SellTicket01();
        SellTicket01 sellTicket02 = new SellTicket01();
        SellTicket01 sellTicket03 = new SellTicket01();

        //会出现超卖现象
        sellTicket01.start();   //启动售票线程
        sellTicket02.start();   //启动售票线程
        sellTicket03.start();   //启动售票线程

    }

    //使用Thread方式
    class SellTicket01 extends Thread{
        private static int ticketNum = 100; //让多个线程共享ticketNum
        @Override
        public void run(){
            while(true){
                if (ticketNum <= 0) {
                    System.out.print("售票结束~~");
                }
                //休眠50毫秒

                try{
                    Thread.sleep(50);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }

                System.out.print("窗口" + Thread.currentThread().getName() 
                    + "售出了一张票" + "剩余票数" + (--ticketNum));
            }
        }
    }
    -------------------------------------------
    public static void main(String[] args) {
        SellTicket02 sellTicket02 = new SellTicket02();

        //也会出现超卖现象
        new Thread(sellTicket02).start();   //第1个线程
        new Thread(sellTicket02).start();   //第2个线程
        new Thread(sellTicket02).start();   //第3个线程
    }

    //实现接口的方式
    class SellTicket02 implements Runnable{
        private int ticketNum = 100;    //让多个线程共享ticketNum
        @Override
        public void run(){
            while(true){
                if (ticketNum <= 0) {
                    System.out.print("售票结束~~");
                }
                //休眠50毫秒

                try{
                    Thread.sleep(50);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }

                System.out.print("窗口" + Thread.currentThread().getName() 
                    + "售出了一张票" + "剩余票数" + (--ticketNum));
            }
        }           
    }
    -------------------------------------------

线程终止:

基本说明:
  1. 当线程完成任务后,会自动退出
  2. 还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式

    public static void main(String[] args) {
    T t1 = new T();
    t1.start();

    //如果希望main线程去控制t1,线程终止,必须可以修改loop
    //让t1退出run方法,从而终止 t1线程 -> 通知方式
    
    //让主线程休眠10秒,再通知t1线程退出
    Thread.sleep(10*1000)
    
    t1.setLoop(false);
    

    }

    class T extends Thread{
    private int count = 0;
    //设置一个控制变量
    private boolean loop = true;
    @Override
    public void run(){
    whlie(loop){
    try{
    Thread.sleep(50);
    }catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.print(“T 运行中~~~” + (++count));
    }
    }
    public void setLoop(boolean loop){
    this.loop = loop;
    }
    }

线程常用方法:

第一组:
  1. setName //设置线程名称,使之与参数name相同
  2. getName //返回该线程的名称
  3. start //使该线程开始执行;java虚拟机底层调用该线程的start0方法
  4. run //调用线程对象run方法
  5. setPriority //更改线程的优先级
  6. getPriority //获取线程的优先级
  7. sleep //在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
  8. interrupt //中断线程(不是终止)
注意事项:
  1. start底层会创建新的线程,调用run,run就是一个简单的方法调用,不会启动新线程
  2. 线程优先级的范围
  3. interrupt,中断线程,但并没有真正的结束线程。所以一般用于中断正在休眠线程
  4. sleep:线程的静态方法,使当前线程休眠
例:
    public static void main(String[] args) {
        /*
            主线程吃了100个包子,开始休眠,然后执行到t.interrupt(),中断休眠,再吃100个包子
        */
        T t = new T();
        t.setName("线程")
        /*
            优先级:
                MAX_PRIORITY    10
                MIN_PRIORITY    1
                NORM_PRIORITY   5
        */
        t.setPriority(Thread.MIN_PRIORITY)
        t.start();  //启动子线程

        //主线程打印5个hi,然后中断 子线程休眠
        for (int i = 0; i < 5; i++) {
            Thread.sleep(1000);
            System.out.print("hi " + i);
        }
        t.interrupt();  //当执行到这里,就会中断,t线程的休眠

    }

    class ThreadDemo1 extends Thread{
        @Override
        public void run(){
            whlie(true){
                for (int i = 0; i <100; i++) {
                    //Thread.currentThread().getName() 获取当前线程名称
                    System.out.print(Thread.currentThread().getName() + "吃包子~~~~~~");
                }
                try{
                    System.out.print(Thread.currentThread.getName() + "休眠中~~~~~~~~");
                    Thread.sleep(20*1000);
                }catch(InterruptedException e){
        //当该线程执行到一个interrupt 方法时,就会catch一个异常,可以加入自己的业务代码
        //InterruptedException 捕获一个中断异常
                    System.out.print(Thread.currentThread().getName() + "被 interrupt了");            
                }
            }
        }
    }
第二组:
  1. yield:线程的礼让。让出cpu,让其他线程执行,但礼让的时间不确定,所以也不一定礼让成功
  2. join:线程的插队。插队的线程一旦插队成功,则肯定先执行完插入的线程所有的任务
例:
    public static void main(String[] args) {
        T2 t2 = new T2();
        t2.start();

        for (int i = 1; i <=20; i++) {
            Thread.sleep(1000);
            System.out.print("主线程(小弟) 吃了 " + i + "包子");
            if (i == 5) {
                System.out.print("主线程(小弟) 让 子线程(老大) 先吃");
                t2.join();  //这里相当于让t2线程先执行完毕
                System.out.print("子线程(老大) 吃完了,主线程(小弟)接着吃");
            }
        }
    }

    class T2 extends Thread{
        @Override
        public void run(){
            for (int i = 1; i <= 20; i++) {
                try{
                    Thread.sleep(1000);
                }catch(InterruptedException){
                    e.printStackTrace();
                }
                System.out.print("子线程(老大) 吃了 " + i + "包子");
            }
        }
    }       
练习:
  1. 主线程每隔1s,输出hi,一共10次
  2. 当输出到 hi5时,启动一个子线程(要求实现Runnable),每隔1s输出hello,等该线程输出10次hello后,退出
  3. 主线程继续输出hi,直到主线程退出

    public static void main(String[] args) {
        Thread t3 = new Thread(new T3());   //创建子线程
        for (int i =1; i <= 10; i++) {
            System.out.print("hi " + i);
            if (i == 5) { //说明主线程输出了5次hi
                t3.start(); //启动子线程,输出 hello
                t3.join();  //立即将t3子线程插入main,让t3先执行
            }
        }
    }
    
    class T3 implements Runnable{
        int count = 0;
        @Override
        public void run(){
            while (true) {
                System.out.print("hello" + (++count));
    
                try{
                    Thread.sleep(1000);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
                if (count == 10) {
                    break;
                }
            }
        }
    }
    
创作不易!转载请注明作者及文章链接或作者博客链接——
- 作者:pidanxia
- 链接:https://pidanxia.ink
(链接可为:**文章链接**或者**作者博客链接**)
暂无评论

发送评论 编辑评论


				
上一篇
下一篇