多线程
线程简介
Process 和 Thread(进程和线程)
-
进程包含多个线程
-
即使自己没有创建线程,后台也会有多个线程,如主线程,GC线程(Garbage Collection)
-
-
线程是CPU调度和执行的基本单位
-
main()称之为主线程,为系统的入口,用于执行整个程序
-
线程的运行和调度器安排调度,调度器是与os紧密相关的,先后顺序不能人为干预
-
-
模拟多线程(单核但是切换快,感觉像是同时运行)
-
真正的多线程(多核)
-
对同一份资源操作时,会存在资源抢夺,需要并发控制
-
线程的使用需要额外开销(CPU调度时间,并发控制开销)
-
线程有自己的工作内存,内存控制不当会造成数据不一致
-
线程创建
-
继承Thread类
-
Runnable接口
-
Callable接口
Thread类
继承Thread类
重写run()方法
调用start开启线程
package com.wang.Thread; //创建线程方式一:继承Thread类,重写run()方法,调用start开启线程 //线程开启不一定立即执行,由CPU调度执行 public class TestThread1 extends Thread { public void run(){ //run方法体 for (int i = 0; i < 200; i++){ System.out.println("我在看代码"+i); } } public static void main(String[] args) { //main 线程,主线程 TestThread1 testThread1 = new TestThread1(); //调用start方法开启线程 testThread1.start(); for (int i = 0; i < 200; i++){ System.out.println("我在学习多线程"+i); } } }
Runnable
Runnable接口
实现Runnable接口
重写run方法
将runnable接口的对象丢入接口
package com.wang.Thread; //创建线程方式二 实现runnable接口,重写run方法 //执行线程丢入接口,调用start() public class TestThread3 implements Runnable{ //重写run方法 public void run(){ //run方法体 for (int i = 0; i < 200; i++){ System.out.println("我在看代码"+i); } } //main 线程,主线程 public static void main(String[] args) { //新建runnable接口的实现类对象 TestThread3 testThread1 = new TestThread3(); //新建线程的对象,参数为runnable对象 Thread thread = new Thread(testThread1); //调用start方法开启线程 thread.start(); for (int i = 0; i < 200; i++){ System.out.println("我在学习多线程"+i); } } }
-
避免了单继承局限性,灵活方便,方便同一个对象被多个线程使用(推荐使用)
案例:龟兔赛跑
package com.wang.Thread; //模拟龟兔赛跑 public class Race implements Runnable{ private static String winner; @Override public void run() { for (int i = 0; i <= 100; i++) { if (Thread.currentThread().getName().equals("兔子")&&i%20==0){ try { Thread.sleep(1); }catch (InterruptedException e){ e.printStackTrace(); } } if (gameOver(i)){ break; } System.out.println(Thread.currentThread().getName()+"跑了"+i+"步"); } } private boolean gameOver(int steps){ if (winner!=null){ return true; }{ if (steps>=100){ winner = Thread.currentThread().getName(); System.out.println("winner is"+winner); return true; } } return false; } public static void main(String[] args) { Race race = new Race(); new Thread(race,"兔子").start(); new Thread(race,"乌龟").start(); } }
Callable(了解即可)
-
需要返回值类型
-
重写call方法,需要抛出异常
package com.wang.Thread.Demo01; import com.wang.Thread.TestThread2; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.concurrent.*; //实现callable接口 public class TestCallable implements Callable<Boolean> { private String url;//网络图片地址 private String name;//保存的文件名 public TestCallable(String url,String name){ this.name = name; this.url = url; } @Override public Boolean call() { WebDownloader webDownloader = new WebDownloader(); webDownloader.downloader(url,name); System.out.println("下载的文件名为:"+name); return true; } public static void main(String[] args) throws ExecutionException, InterruptedException { TestCallable testThread1 = new TestCallable("https://i0.hdslb.com/bfs/sycp/creative_img/202108/5a5e381e2e58c3a863b423e2b4fc4eb2.jpg","gou1"); TestCallable testThread2 = new TestCallable("https://i0.hdslb.com/bfs/sycp/creative_img/202108/5a5e381e2e58c3a863b423e2b4fc4eb2.jpg","gou2.jpg"); TestCallable testThread3 = new TestCallable("https://i0.hdslb.com/bfs/sycp/creative_img/202108/5a5e381e2e58c3a863b423e2b4fc4eb2.jpg","gou3"); TestCallable testThread4 = new TestCallable("https://i0.hdslb.com/bfs/sycp/creative_img/202108/5a5e381e2e58c3a863b423e2b4fc4eb2.jpg","gou4"); //创建执行服务 ExecutorService ser = Executors.newFixedThreadPool(4); //提交执行 Future<Boolean> r1 = ser.submit(testThread1); Future<Boolean> r2 = ser.submit(testThread2); Future<Boolean> r3 = ser.submit(testThread4); Future<Boolean> r4 = ser.submit(testThread4); //获取结果 boolean rs1 = r1.get(); boolean rs2 = r2.get(); boolean rs3 = r3.get(); boolean rs4 = r4.get(); //关闭服务 ser.shutdown(); } } class WebDownloader{ public void downloader(String url,String name){ try { FileUtils.copyURLToFile(new URL(url),new File(name)); }catch (IOException e){ e.printStackTrace(); System.out.println("IO异常,downloader方法"); } }}
静态代理
-
真实对象和代理对象都要实现同一个接口
-
代理对象要代理真实角色
-
代理对象可以做很多真实对象做不了的事情
-
真实对象专注做自己的事情
package com.wang.proxy; public class StaticProxy { public static void main(String[] args) { WeddingCompany weddingCompany = new WeddingCompany(new You()); weddingCompany.HappyMarry(); //Thread代理runnable对象 new Thread(()-> System.out.println("我愿意")).start(); } } interface Marry{ // void HappyMarry(); } //真实角色,你去结婚 class You implements Marry{ @Override public void HappyMarry() { System.out.println("结婚了"); } } //婚庆公司代理结婚 class WeddingCompany implements Marry{ private Marry target; @Override public void HappyMarry() { before(); this.target.HappyMarry(); after(); } public WeddingCompany(Marry target){ //真实对象的结婚 this.target = target; } private void after(){ System.out.println("收尾款"); } private void before(){ System.out.println("布置婚礼现场"); } }
Lambda表达式
避免匿名内部类定义过多
代码看起来更简洁
去掉了一堆无意义的代码,只留下核心逻辑
函数式接口
-
任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口
-
对于函数式接口,我们可以通过lambda表达式来创建该接口的对象
lambda的优化过程:
package com.wang.lambda; /* 推到lambda表达式 */ public class TestLambda01 { //3.用静态内部类实现方法 static class Like2 implements ILike{ @Override public void lambda() { System.out.println("lambda2"); } } public static void main(String[] args) { ILike like = new Like(); like.lambda(); like = new Like2(); like.lambda(); //4.局部内部类 class Like3 implements ILike{ @Override public void lambda() { System.out.println("lambda3"); } } like = new Like3(); like.lambda(); //5.匿名内部类,没有类的名称,必须借助接口或者父类,此例中ILike就是接口 ILike like5 = new ILike() { @Override public void lambda() { System.out.println("lambda4"); } }; like5.lambda(); //用lambda简化,接口只有一个类且只有一个方法 like = ()-> { System.out.println("lambda5"); }; like.lambda(); } } //1.定义一个函数式接口 interface ILike{ void lambda(); } //2.实现接口 class Like implements ILike{ @Override public void lambda() { System.out.println("lambda"); } }
package com.wang.lambda; public class TestLambda02 { public static void main(String[] args) { Ilove ilove = (int a)->{ System.out.println("I LOVE U"+a); }; //lambda简化 1 参数类型可消去 Ilove love = (a)->{ System.out.println("OOOO"); }; //简化 2 括号可去 Ilove love2 = a->{ System.out.println("QQQQQ"+a); }; //简化 3 去掉花括号 Ilove love3 = a-> System.out.println("QQQQQ"+a); love3.love(521); //总结: //多行就带上花括号,单行功能才能去掉花括号 //函数式接口才可以用lambda接口 //多参数必须要带括号 // } } interface Ilove{ void love(int a); }
线程的切换