静态代理 结婚案例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 package ml.guest997;public class StaticProxy { public static void main (String[] args) { Company company = new Company(new Person()); company.work(); } } interface Marry { void work () ; } class Person implements Marry { @Override public void work () { System.out.println("人结婚了" ); } } class Company implements Marry { private Person person; public Company (Person person) { this .person = person; } @Override public void work () { before(); person.work(); after(); } private void before () { System.out.println("公司处理结婚前事务" ); } private void after () { System.out.println("公司处理结婚后事务" ); } }
可以看到代理对象的创建类似于线程创建时传了个实现 Runnable 接口的类对象。
Lambda 表达式 为什么要使用 Lambda 表达式?
避兔匿名内部类定义过多 可以让代码看起来很简洁 只留下核心的逻辑 什么时候能够使用 Lambda 表达式?
什么是函数式接口?
以前的代码实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 package ml.guest997;public class LambdaTest01 { static class Talk02 implements ITalk { @Override public void talk () { System.out.println("talk02" ); } } public static void main (String[] args) { new Talk01().talk(); new Talk02().talk(); class Talk03 implements ITalk { @Override public void talk () { System.out.println("talk03" ); } } new Talk03().talk(); ITalk talk04 = new ITalk() { @Override public void talk () { System.out.println("talk04" ); } }; talk04.talk(); } } interface ITalk { void talk () ; } class Talk01 implements ITalk { @Override public void talk () { System.out.println("talk01" ); } }
有些代码只会使用到一次,之前就能使用如上面的方法来简化代码。而 java8 之后提供了新的方式来简化代码。
Lambda 简化代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package ml.guest997; public class LambdaTest02 { public static void main(String[] args) { //标准 Lambda 语法 ISay say01 = (String name ) -> { System .out .println(name + " say01"); }; say01.say("01"); //简化一:去掉全部参数类型 ISay say02 = (name ) -> { System .out .println(name + " say02"); }; say02.say("02"); //简化二:去掉括号(需要只有一个参数) ISay say03 = name -> { System .out .println(name + " say03"); }; say03.say("03"); //简化三:去掉花括号(需要代码只有一行) ISay say04 = name -> System .out .println(name + " say04"); say04.say("04"); } } //函数式接口 interface ISay { void say(String name ); }
可以看到通过 Lambda 简化后的代码甚至可以短到只有一行。
线程状态
线程只能启动一次,一旦死亡就不能再次启动。
线程停止 不推荐使用 JDK 提供的方法。推荐让线程自己停下来。使用一个标志位当作终止变量,如当 flag = false 时线程终止。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package ml.guest997; public class StopTest implements Runnable { private boolean flag = true ; public static void main (String [] args) { StopTest stopTest = new StopTest (); new Thread (stopTest).start (); for (int i = 0 ; i < 1000 ; i++) { System.out.println ("main" + i); if (i == 500 ) { stopTest.stop (); } } } @Override public void run () { int i = 0 ; while (flag) { System.out.println ("running" + i++); } } private void stop () { this .flag = false ; System.out.println ("线程停止了" ); } }
线程休眠 休眠可以模拟网络延时和倒计时。每一个对象都有一个锁,休眠不会释放锁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 package ml.guest997; import java.text.SimpleDateFormat;import java.util.Date;public class SleepTest { public static void main(String[] args) { SleepTest sleepTest = new SleepTest(); System .out .println("每隔一秒输出当前时间"); sleepTest.nowTime(); System .out .println("十秒倒计时"); sleepTest.countDown(); } public void nowTime() { Date date = new Date (System .currentTimeMillis()); int i = 0 ; while (i < 5 ) { try { System .out .println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date )); Thread.sleep(1000 ); date = new Date (System .currentTimeMillis()); i++; } catch (InterruptedException e) { e.printStackTrace(); } } } public void countDown() { try { for (int i = 10 ; i >= 0 ; i System .out .println(i); Thread.sleep(1000 ); } } catch (InterruptedException e) { e.printStackTrace(); } } }
线程礼让 线程礼让就是让运行中的线程暂停,但不是进入阻塞状态,而是进入就绪状态,与其它线程回到同一起跑线。所以礼让不一定会成功,看 CPU 的调度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package ml.guest997; public class YieldTest implements Runnable { public static void main(String[] args) { YieldTest yieldTest = new YieldTest() ; new Thread(yieldTest , "A" ) .start() ; new Thread(yieldTest , "B" ) .start() ; } @Override public void run() { System . out.println(Thread . currentThread() .getName() + "线程开始" ); Thread . yield() ; System . out.println(Thread . currentThread() .getName() + "线程结束" ); } }
线程合并 线程合并可以想象为插队,只有当插队的线程运行完才能运行其它线程,其它线程会处于阻塞状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package ml.guest997;public class JoinTest implements Runnable { @Override public void run () { for (int i = 0 ; i < 10 ; i++) { System.out.println("使用线程" + i); } } public static void main (String[] args) { JoinTest joinTest = new JoinTest(); Thread thread = new Thread(joinTest); thread.start(); try { for (int i = 0 ; i < 10 ; i++) { System.out.println("使用 main 线程" + i); if (i == 5 ) { thread.join(); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
线程优先级 线程优先级从1到10,1最低,10最高。当线程的优先级没有指定时,所有线程都为普通优先级(5)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 package ml.guest997; public class PriorityTest implements Runnable { @Override public void run() { for (int i = 0 ; i < 10 ; i++) { System . out.println(Thread . currentThread() .getName() + i); } } public static void main(String[] args) { System . out.println("main 线程优先级:" + Thread . currentThread() .getPriority() ); Thread t1 = new Thread(new PriorityTest() , "one" ); Thread t2 = new Thread(new PriorityTest() , "two" ); Thread t3 = new Thread(new PriorityTest() , "three" ); t1.setPriority(6) ; t3.setPriority(4) ; t1.start() ; t2.start() ; t3.start() ; } }
可以从结果看出,不是高优先级的线程就一定先比低优先级的线程先运行完,而是高优先级的线程先运行的概率比低优先级的线程高。
守护线程 线程分为用户线程和守护线程,虚拟机必须确保用户线程执行完毕,但是不用等待守护线程执行完毕 。守护线程有如后台记录操作日志、监控内存和垃圾回收等待。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 package ml.guest997; public class DaemonTest { public static void main(String [] args) { Thread daemonThread = new Thread(() -> { while (true ) { System.out.println("守护线程一直运行" ); } }) ; Thread userThread = new Thread (() -> { for (int i = 0 ; i < 3 ; i++) { System.out.println("用户线程运行" + i); } }) ; userThread .setPriority (10 ) ; userThread .start () ; daemonThread .setDaemon (true ) ; //设置线程为守护线程 daemonThread .start () ; } } /*结果为 用户线程运行0 用户线程运行1 用户线程运行2 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 守护线程一直运行 Process finished with exit code 0*/