多线程学习笔记(二)静态代理及线程状态

首先代理是一种模式,提供了对目标对象的间接访问方式,即通过代理访问目标对象。如此便于在目标实现的基础上增加额外的功能操作,前拦截,后拦截等,以满足自身的业务需求,同时代理模式便于扩展目标对象功能的特点也为多人所用。
图形描述
在这里插入图片描述
静态代理的实现比较简单,代理类通过实现与目标对象相同的接口,并在类中维护一个代理对象。通过构造器塞入目标对象,赋值给代理对象,进而执行代理对象实现的接口方法,并实现前拦截,后拦截等所需的业务功能。

/**
 * 静态代理
 * 1.真实角色
 * 2.代理角色
 * 都需实现同一个接口
 */
public class StaticProxy {
    public static void main(String[] args) {
        new WebCompany(new ME()).happyMarry();
    }
}
interface Marry{
    void happyMarry();
}
//真实角色
class ME implements Marry{

    @Override
    public void happyMarry() {
        System.out.println("love forever");
    }
}
//代理角色
class WebCompany implements Marry{
    //真实角色
    private Marry target;
    public WebCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void happyMarry() {
        before();
        this.target.happyMarry();
        after();
    }
    private void before(){
        System.out.println("哼唧哼唧");
    }
    private void after(){
        System.out.println("去死");
    }
}

额,不要在意打印的东西。
在这里插入图片描述

优势在于可以做到不对目标对象进行修改的前提下,对目标对象进行功能的扩展和拦截。
  但因为代理对象需要实现与目标对象一样的接口,会导致代理类十分繁多,不易维护,同时一旦接口增加方法,则目标对象和代理类都需要维护。
  与之相对的会有动态代理,这个我之后再看

线程状态:
在这里插入图片描述
然后我们可以看一看api文档对线程状态的描述
在这里插入图片描述
这两张图应该差不多能反应线程的生命周期,我们来看一看编译器是如何得到这些信息的

import java.lang.Thread.State;
public class AllState {
    public static void main(String[] args) throws InterruptedException {
        Thread th = new Thread(()->{
            for (int i=0;i<5;i++){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("emmmmmm");
            }
        });

        //观察状态,获取并打印
       State state = th.getState();
       System.out.println(state);
       //获取活跃线程数
        int count = Thread.activeCount();
        System.out.println(count );

        th.start();
        state = th.getState();
        System.out.println(state);
        //获取活跃线程名称
        Thread.currentThread().getThreadGroup().list();

       while (state != State.TERMINATED){
           Thread.sleep(200);
           state = th.getState();
           System.out.println(state);
           count = Thread.activeCount();
           System.out.println(count );
       }
       Thread.currentThread().getThreadGroup().list();
    }
}

我们来看运行结果
在这里插入图片描述
在这里插入图片描述
是不是很诧异只创建了一个线程结果显示的是两个,加上主线程是三个
我们可以从这句代码看出一些端倪

Thread.currentThread().getThreadGroup().list();

将活跃线程转化成列表输出,
我们可以看到在用户线程和主线程之外有一个Monitor Ctrl-Break这个线程,这是idea编译器自己的事情,debug之后就是正常数据,eclipse跑过也是正常数据。所以我们不用去管,知道idea默认有一条线程就行了。

所以我们可以看到 run()是线程的new阶段,start()是runnable阶段,sleep是TIMED_WAITING阶段,直到线程结束的阶段。需要注意的是,我们结束线程,并不能使用stop方法,因为在API文档中现实已过时,也就是说,要么有bug,要么不安全。
那么,我们就可以使用标志量来进行线程处理

/***
 * 中止线程方式
 * 1.线程正常执行完毕
 * 2.加入标志位
 */
public class StatusThread implements Runnable{
    private boolean flag = true;
    private String name;

    @Override
    public void run() {
        int i=0;
        //关联标识
        while(flag){
            System.out.println(name+"-->"+i++);
        }
    }

    public StatusThread(String name) {
        this.name = name;
    }

    //改变标识
    public void setflag(){
        this.flag = false;
    }

    public static void main(String[] args) {
        StatusThread st = new StatusThread("Ronaldo goal");
        new Thread(st).start();

        for (int i=0;i<100;i++){
            if(i==88){
                st.setflag();//改变标志量,使循环中止,从而线程不会执行
                System.out.println("wonderful");
            }
            System.out.println("messi");
        }
    }
}

在这里插入图片描述
在这里插入图片描述
可以看到死循环的线程已结束。
我们来看看高风亮节的yield和强行插队的join的差别

**
 * yield重新回到就绪状态,非阻塞状态
 */
public class YieldTest {
    public static void main(String[] args) {
        MyYield myYield = new MyYield();
        new Thread(myYield,"you").start();
        new Thread(myYield,"me").start();
    }
}

class MyYield implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->start");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"-->end");
    }
}

在这里插入图片描述
yield()使自己重新进入就绪状态,而将资源交给下一个线程使用,随后两个线程开始竞争资源。

/**
 * join方法测试
 */
class JOIN extends Thread{
    private String name;

    public JOIN(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(name+"-->"+"开始");
        for (int i=0;i<10;i++){
            System.out.println("子线程"+name+"运行"+i);
            try {
                if(i==9){
                    System.out.println(name+": 结束");
                }
                int j = (int)Math.random()*10;
                Thread.sleep(j);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
       // System.out.println(name+": 结束");
    }
}
public class joinTest {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName()+"开始运行");
        JOIN j = new JOIN("A");
        JOIN x = new JOIN("B");
        j.start();
        x.start();
        try {
            j.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            x.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+": zhu结束");
    }
}

在这里插入图片描述
强行插入main线程中间,使得main线程在用户线程结束后继续执行。

所以,yield是让别人插队,而join是自己插队。一攻一守,完美。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值