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