2.5 静态代理模式
多线程 Thread 为代理,Runnable 为被代理对象!底层就是动态代理
package com.example.democrud.democurd.test01; /** * //静态代理模式 * //真实对象和代理对象都要实现同一接口 * //代理对象 必须要代理真实对象 * //好处: * //代理对象可以做很多真实对象做不了的事情 * //真实对象专注于做自己的事情 */ public class testThred06 { public static void main(String[] args) { You you = new You(); WeddingCompany company = new WeddingCompany(you); company.HappyMarry(); new Thread( ()-> {System.out.println("我爱你");} ).start(); new Thread( ()-> System.out.println("我爱你") ).start(); // new Thread(Runnable::run).start(); new WeddingCompany(you).HappyMarry(); // 2个用法一样,都是静态代理 } } interface Marry{ void HappyMarry(); } class You implements Marry{ @Override public void HappyMarry() { System.out.println("老王要结婚不知道他开心不"); } } //代理角色,婚庆公司,帮助你结婚 class WeddingCompany implements Marry{ //代理对象-->真实目标角色 private Marry target; public WeddingCompany(Marry target){ this.target=target; } @Override public void HappyMarry() { before(); this.target.HappyMarry(); after(); } private void after() { System.out.println("结婚后"); } private void before() { System.out.println("结婚前"); } }
3、线程的6种状态
线程有6种状态,下面有错误: public enum State { //线程刚创建 NEW, //在JVM中正在运行的线程 RUNNABLE, //线程处于阻塞状态,等待监视锁,可以重新进行同步代码块中执行 BLOCKED, //等待状态 WAITING, //调用sleep() join() wait()方法可能导致线程处于等待状态 TIMED_WAITING, //线程执行完毕,已经退出 TERMINATED; }
package com.example.democrud.democurd.test01; //观察 线程的状态 public class testState { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(()->{ for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("---等待结束"); } }); //观察线程的状态 NEW Thread.State state = thread.getState(); System.out.println(state); //观察线程的状态 RUNNABLE thread.start(); state = thread.getState(); System.out.println(state); //终止线程的线程状态。线程已完成执行。 只要线程不停止运行他就会进入到此处进行运行 while (state!=Thread.State.TERMINATED){ Thread.sleep(100); state = thread.getState();//TIMED_WAITING System.out.println(state); } } }
BLOCKED是指线程正在等待获取锁;WAITING是指线程正在等待其他线程发来的通知(notify),收到通知后,可能会顺序向后执行(RUNNABLE),也可能会再次获取锁,进而被阻塞住(BLOCKED)。
3.1 线程的一些常用方法
(Thread t = new Thread)线程 t 的一些方法如下图所示:
线程中常用的方法
1、public void start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
2、public void run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run
方法;否则,该方法不执行任何操作并返回。
3、public final void setName(String name) 改变线程名称,使之与参数 name 相同
4、public final void setPriority(int piority) 更改线程的优先级。
5、public final void setDaemon(boolean on) 将该线程标记为守护线程或用户线程。
6、public final void join(long millisec) 等待该线程终止的时间最长为 millis 毫秒。
7、public void interrupt() 中断线程。
8、public final boolean isAlive() 测试线程是否处于活动状态。
9、public static void static yield() 暂停当前正在执行的线程对象,并执行其他线程。
10、public static void sleep(long millisec) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
11、public static Thread currentThread() 返回对当前正在执行的线程对象的引用。
配一张图:
3.1.1 线程休眠——sleep()
- sleep(时间)指定当前线程阻塞的毫秒数;
- sleep 存在异常 InterruptedException;
- sleep 时间达到后线程进入就绪状态;
- sleep 可以模拟网络延时,倒计时等;
- sleep 每一个对象都有一个锁,sleep 不会释放锁;
sleep() 方法的用处
package com.example.democrud.democurd.test01; import java.text.SimpleDateFormat; import java.util.Date; public class testSleep { public static void main(String[] args) throws InterruptedException { // tenDown(); testDate(); } public static void testDate() throws InterruptedException { Date date = new Date(System.currentTimeMillis());//获取系统当前的时间 while (true){ //休眠1秒 Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:mm:ss").format(date)); //上面就获取了一次 每过1s咱们就需要更新一次 date=new Date(System.currentTimeMillis());//更新当前的时间 } } //数字倒计时demo public static void tenDown() { int num = 10; try { while (true) { Thread.sleep(1000); System.out.println(num--); if (num < 0) { break; } } } catch (Exception e) { e.printStackTrace(); } } }
主线程调用子线程的interrupt()方法,导致子线程抛出InterruptedException, 在子线程中catch这个Exception,不做任何事即可从Sleep状态唤醒线程,继续执行。
//new 一个线程 Thread thread = new Thread(new TestThread(1)); //开启线程 thread .start(); try { //休眠 Thread.sleep(3000); //结束休眠开始继续运行 thread .interrupt(); } catch (InterruptedException e) { e.printStackTrace(); }
\
3.1.2 线程礼让——yield()
- 礼让线程,让当前正在执行的线程暂停,但不阻塞;
- 将线程从运行状态转为就绪状态;
- 让 CPU 从新调度,有可能还是调度该礼让线程。
package com.example.democrud.democurd.test01; public class testyield { public static void main(String[] args) { yield yield = new yield(); new Thread(yield,"a").start(); new Thread(yield,"B").start(); } } class yield implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"开始执行"); //礼让线程 但是不一定礼让就会成功是一个概率的事件 //礼让线程,并不能一定成功礼让,只能让运行状态线程变为就绪状态,重新竞争,看CPU心情 Thread.yield(); System.out.println(Thread.currentThread().getName()+"结束执行"); } }
3.1.3 合并线程——Join()
Join 合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞。
可以想象成插队。
package com.example.democrud.democurd.test01; //测试Join方法 //想象为插队 //Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞 public class TestJoin { public static void main(String[] args) throws InterruptedException { Join join = new Join(); Thread thread = new Thread(join); thread.start(); for (int i = 0; i < 50; i++) { if (i==30){ //join插队优先进行运行 thread.join(); } System.out.println("main"+i); } } } class Join implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("我是vip的线程"); } } }
3.2 停止线程的方式
第一种:标志位
- 不推荐使用 JDK 提供的 stop ()、destroy()方法。【已弃用】
- 推荐线程自己停止下来
- 建议使用一个标志位进行终止变量 , 当 flag == false,则终止线程运行。
线程的停止
package com.example.democrud.democurd.test01; //测试stop //1.建议线程正常停止--->利用次数,不建议死循环。 //2.建议使用标志位--->设置一个标志位. //3.不要使用stop或destroy等过时或JDK不建议使用的方法 public class testStop implements Runnable { private Boolean flag = true; @Override public void run() { int i = 0; while (flag) { System.out.println("执行线程任务进行中"+i++); } } public void stop() { this.flag = false; } public static void main(String[] args) { testStop stop = new testStop(); new Thread(stop).start(); for (int i = 0; i < 100; i++) { System.out.println("main"+i); if (i == 90) { stop.stop(); System.out.println("执行到90停止"); } } } }
第二种: interrupt方法
1、直接调用interrupt()方法
package com.example.democrud.democurd.test01; public class testStop01 { public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(()->{ //直接调用interrupt while (!Thread.interrupted()){ System.out.println("你好啊"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); //加入break才是终止执行 break; } } System.out.println("停止"); }); t1.start(); Thread.sleep(2000); System.out.println("终止"); //让t1终止 使用此方法 t1.interrupt(); } }
2、拿到当前线程在调用interrupt()方法(Thread.currentThread().isInterrupted())
public class ThreadDemo14 { public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(()->{ //拿到当前线程 判断是否终止 while (!Thread.currentThread().isInterrupted()){ System.out.println("别烦我"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); //加入break才是终止执行 break; } } System.out.println("转账终止"); }); t1.start(); Thread.sleep(2000); System.out.println("有内鬼终止交易"); //让t1终止 使用此方法 t1.interrupt(); } }
注:当调用interrupt方法时,一定要加上break终止代码否则只会出现暂时终止。\
调用interrupt()方法的两种方法的区别
Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志,也就是复位
public class ThreadDemo16 { public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(()->{ while (!Thread.interrupted()){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); //获取当前线程 Thread curr=Thread.currentThread(); System.out.println("打印当前线程状态"+curr.isInterrupted()); System.out.println("打印当前线程状态"+curr.isInterrupted()); System.out.println("---------------------"); Thread.interrupted(); //Thread.currentThread().interrupt(); System.out.println("打印当前线程状态"+curr.isInterrupted()); System.out.println("打印当前线程状态"+curr.isInterrupted()); } } }); t1.start(); Thread.sleep(1000); t1.interrupt(); } }
Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志,不会复位
public class ThreadDemo16 { public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(()->{ while (!Thread.interrupted()){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); //获取当前线程 Thread curr=Thread.currentThread(); System.out.println("打印当前线程状态"+curr.isInterrupted()); System.out.println("打印当前线程状态"+curr.isInterrupted()); System.out.println("---------------------"); // Thread.interrupted(); Thread.currentThread().interrupt(); System.out.println("打印当前线程状态"+curr.isInterrupted()); System.out.println("打印当前线程状态"+curr.isInterrupted()); } } }); t1.start(); Thread.sleep(1000); t1.interrupt(); } }
打印结果
补:线程中的重要属性 public class ThreadDemo11 { public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(()->{ for (int i=0;i<10;i++){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }); //重要属性 System.out.println("线程的ID:"+t1.getId()); System.out.println("线程的名称:"+t1.getName()); System.out.println("线程的优先级:"+t1.getPriority()); System.out.println("线程的状态:"+t1.getState()); System.out.println("线程的类型:"+t1.isDaemon()); System.out.println("线程是否存活:"+t1.isAlive()); t1.start();