多线程
-
很多多线程是模拟出来的,真正的多线程是只有多个cpu,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉。
-
线程是独立执行的路径
-
在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程(垃圾收集器)
-
main()称之为主线程,为系统的入口,用于执行整个程序
-
在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的干预的
-
对同一份资源操作时,会存在资源抢夺的问题,所以需要加入并发控制。
-
线程会带来额外的开销,如cpu调度时间,并发控制开销。
-
每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
线程创建(Thread、Runnable、Callable)
-
Thread class
-
自定义线程类继承Thread类
-
重写run()方法,编写线程执行体
-
创建线程对象,调用start()方法启动线程
-
run方法体和主线程是同一时间交替运行
-
线程开启不一定立即执行,由cpu调度执行
package com.whd.Thread; public class TestThread1 extends Thread{ //创建线程方式一: 继承Thread类,重写run()方法,调用start开启线程 @Override public void run() { //run 方法线程体,必须进行写 for (int i = 0; i < 20; i++) { System.out.println("whd"+ i); } } public static void main(String[] args) { //main线程,主线程 //创建一个线程对象 TestThread1 testThread1 = new TestThread1(); //调用start方法开启线程,调用start方法才可以使主线程和其他线程同时开启 testThread1.start(); // 主线程方法: for (int i = 0; i < 20; i++) { System.out.println("yxy" + i); } } }
下载图片
package com.whd.Thread; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.URL; //实现下载图片 public class TestThread2 extends Thread{ // 继承Thread类创建一个进程类 private String url; private String name; //重写构造函数 -- 有参构造 public TestThread2(String url, String name){ this.url = url; this.name = name; } //重写run方法(必须) public void run(){ // 构造一个下载器 WebDownloader webDownloader = new WebDownloader(); //传递参数 webDownloader.downloader(url, name); System.out.println("下载了文件名为"+name); } //main方法 public static void main(String[] args) { TestThread2 testThread2 = new TestThread2("https://i2.hdslb.com/bfs/archive/e84e4a477a84998d3920d28819380224770b34f5.jpg@412w_232h_1c.jpg","图片1"); testThread2.start(); } } //下载器 class WebDownloader{ //下载方法 public void downloader(String url, String name){ try{ //利用copyURLToFile进行下载 FileUtils.copyURLToFile(new URL(url), new File(name)); }catch (IOException e){ e.printStackTrace(); System.out.println("IO异常"); } } }
-
-
Runnable 接口
-
定义MyRunnable类实现Runnable接口
-
实现run()方法,编写线程执行体
-
创建线程对象,调用start()方法启动线程
调用Runnable接口创建进程
package com.whd.Runnable; import com.whd.Thread.TestThread1; //创建线程方式2: 实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法 public class TestTread02 implements Runnable{ //创建线程方式一:继承Thread类,重写run()方法,调用start开启线程 @Override public void run() { //run 方法线程体 for (int i = 0; i < 20; i++) { System.out.println("whd"+ i); } } //main线程,主线程 public static void main(String[] args) { //创建runnable接口的实现类对象 TestTread02 testTread02 = new TestTread02(); //创建线程对象,通过线程对象来开启我们的线程,代理 Thread thread = new Thread(); //调用start方法开启线程 thread.start(); //简写的方法 new Thread(testTread02).start(); // 主线程方法: for (int i = 0; i < 20; i++) { System.out.println("yxy" + i); } } }
利用Runnable接口下载图片:
package com.whd.Runnable; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.URL; //利用runnable接口创建线程, 下载图片 public class Down implements Runnable{ private String url; private String name; public Down(String url, String name){ this.url = url; this.name = name; } public void run(){ WebDownloader webDownloader = new WebDownloader(); webDownloader.downloader(url, name); System.out.println("下载了"+ name); } public static void main(String[] args) { Down down = new Down("https://i2.hdslb.com/bfs/archive/e84e4a477a84998d3920d28819380224770b34f5.jpg@412w_232h_1c.jpg","图片1"); //创建一个Thread对象,传入线程对象,调用Thread中的方法 new Thread(down).start(); } } 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异常"); } } }
-
-
并发问题
package com.whd.Runnable; //多个线程同时操作一个对象 //买火车票的例子 public class TestThread3 implements Runnable { private int ticketNums = 10; @Override public void run() { while (true){ if(ticketNums <= 0){ break; } //设置延时 try{ Thread.sleep(200); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "拿到了" + ticketNums-- + "票"); } } public static void main(String[] args) { TestThread3 ticket = new TestThread3(); new Thread(ticket, "1").start(); new Thread(ticket, "2").start(); new Thread(ticket, "3").start(); } } //产生了线程不安全问题,多个线程争夺同一个资源
龟兔赛跑
package com.whd.Runnable; 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("rabbit") && i % 10 == 0){ try { Thread.sleep(2); } catch (InterruptedException e){ e.printStackTrace(); } } //判断比赛是否结束 boolean flag = gameOver(i); if(flag == true){ break; } System.out.println(Thread.currentThread().getName() + "跑了" + i + "步"); if(i == 99){ System.out.println(Thread.currentThread().getName() + "is winner"); } } } //判断是否完成比赛 private boolean gameOver(int steps){ if(winner != null){ return true; }else 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, "rabbit").start(); new Thread(race, "turtle").start(); } }
-
Callable 接口
-
继承callable接口,需要返回值类型
-
重写call方法
-
创建目标对象
-
创建执行服务:ExecutoService ser = Exercutors.newFixedThreadPool(1);
-
提交执行:Future<Boolean> result1 = ser.submit(t1);
-
获取结果:boolean r1 = result1.get()
-
关闭服务:ser.shuidownNow();
-
静态代理模式
package com.whd; //静态代理模式总结: //真实对象和代理对象都要实现同一个接口 //代理对象要代理真实角色 //创建一个静态代理类 public class StaticProxy { public static void main(String[] args) { WeddingCompany weddingCompany = new WeddingCompany(new You()); weddingCompany.HappyMarry(); } } //定义一个接口 interface Marry { void HappyMarry(); } //创建真实结婚对象类,继承该接口,同时实现HappyMarry方法 class You implements Marry { @Override public void HappyMarry() { System.out.println("happy"); } } //创建婚庆公司类(代理),继承Marry接口 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 before() { System.out.println("before"); } private void after() { System.out.println("after"); } }
Lamda表达式
-
实质是属于函数式编程
-
函数式 接口:
-
只包含唯一一个抽象方法,那么它就是一个函数式接口
-
对于函数式接口,可以通过lamda表达式创建接口的对象
-
package com.whd.Lambda; /* 推导lambda表达式 */ public class TestLambda { //3.静态内部类 static class Like2 implements ILike{ @Override public void lambda() { System.out.println("i like 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("i like lambda3"); } } like = new Like3(); like.lambda(); //5. 匿名内部类,没有类的名称,必须借助接口或者父类 like = new ILike() { @Override public void lambda() { System.out.println("i like lambda4"); } }; like.lambda(); //6.用lambda简化 like = () -> { System.out.println("i like lambda5"); }; like.lambda(); } } // 1.定义一个函数式接口 interface ILike{ void lambda(); } // 2.实现类 class Like implements ILike{ @Override public void lambda() { System.out.println("i like lambda"); } }
-