线程的创建
三种创建方式
继承Thread类
继承Thread类实现多线程步骤如下:
- 自定义线程类继承Thread类
- 重写run() 方法,编写线程执行体
- 创建线程对象,调用start() 方法启动线程
创建线程方式1:继承Thread(通过查看源码发现Thread 是实现Runnable接口的)
注意:线程开启不一定立即执行,由CPU调度安排。
package com.y.demo01;
//创建线程方式一: 继承 Thread类, 重写run()方法, 调用start()开始线程
//总结:注意,线程开启不一定立即执行, 有CPU调度执行
public class TestThread1 extends Thread{
@Override
public void run() {
// run()方法 线程体
for (int i = 0; i < 20; i++) {
System.out.println("我在撸代码" + i);
}
}
public static void main(String[] args) {
// main线程,主线程
TestThread1 thread1 = new TestThread1();
thread1.start();
for (int i = 0; i < 60; i++) {
System.out.println("我在学习"+ i);
}
}
}
案例:网图下载
package com.y.demo01;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//练习 Thread, 实现多线程同步下载图片
public class TestThread2 extends Thread{
private String url;
private String name;
public TestThread2(String url,String name){
this.url = url;
this.name = name;
}
//线程的执行体
@Override
public void run() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,name);
System.out.println("下载了文件名为:"+name);
}
public static void main(String[] args) {
TestThread2 testThread21 = new TestThread2("https://i0.hdslb.com/bfs/archive/756f7695bcdd43e45bf2313a01b9194bc637d788.jpg@640w_400h_100Q_1c.webp","1.jpg");
TestThread2 testThread22 = new TestThread2("https://i0.hdslb.com/bfs/archive/756f7695bcdd43e45bf2313a01b9194bc637d788.jpg@640w_400h_100Q_1c.webp","2.jpg");
TestThread2 testThread23 = new TestThread2("https://i0.hdslb.com/bfs/archive/756f7695bcdd43e45bf2313a01b9194bc637d788.jpg@640w_400h_100Q_1c.webp","3.jpg");
testThread21.start();
testThread22.start();
testThread23.start();
}
}
//下载器
class WebDownloader {
//下载方法
public void downloader(String url, String name){ //下载器
try {
//文件单元.复制URL文件
// 把一个url变成一个文件
FileUtils.copyURLToFile( new URL(url), new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常,downloader方法出现问题");
}
}
}
实现Runnable接口
-
定义MyRunnable类实现Runnable接口
-
实现**run()**方法,编写线程执行体
-
创建线程对象,调用**start()**方法启动线程
package com.y.demo01;
//创建线程方式2:实现 Runnable 接口, 重写run方法, 执行线程需要丢入 Runnable 接口实现类, 调用start方法
public class TestThread3 implements Runnable{
@Override
public void run() {
// run()方法 线程体
for (int i = 0; i < 20; i++) {
System.out.println("我在撸代码" + i);
}
}
public static void main(String[] args) {
// main线程,主线程
TestThread3 thread3 = new TestThread3();
// Thread thread = new Thread(thread3);
// thread.start();
//简写
new Thread(thread3).start();
for (int i = 0; i < 60; i++) {
System.out.println("我在学习"+ i);
}
}
}
Thread 和Runnable小结
继承Thread类
1.子类继承Thread 类具有多线程能力
2.启动线程:子类对象.start()
3.不建议使用:避免OOP单继承局限性
实现Runnable 接口
1.实现接口Runnable 具有多线程能力
2.启动线程:传入目标对象+Thread对象.start()
3.推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
创建线程方式3:
实现Callable 接口
-
实现Callable接口,需要返回值类型
-
重写call 方法,需要抛出异常
-
创建目标对象
-
创建执行服务:
-
提交执行:
-
获取结果:
-
关闭服务:
package com.y.demo02; import com.y.demo01.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.url = url; this.name = name; } //线程的执行体 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 t1 = new TestCallable("https://i0.hdslb.com/bfs/archive/756f7695bcdd43e45bf2313a01b9194bc637d788.jpg@640w_400h_100Q_1c.webp","1.jpg"); TestCallable t2 = new TestCallable("https://i0.hdslb.com/bfs/archive/756f7695bcdd43e45bf2313a01b9194bc637d788.jpg@640w_400h_100Q_1c.webp","2.jpg"); TestCallable t3 = new TestCallable("https://i0.hdslb.com/bfs/archive/756f7695bcdd43e45bf2313a01b9194bc637d788.jpg@640w_400h_100Q_1c.webp","3.jpg"); //创建执行服务: 需要创建一个池子 ExecutorService ser = Executors.newFixedThreadPool(3); //提交执行: Future<Boolean> r1 = ser.submit(t1); Future<Boolean> r2 = ser.submit(t2); Future<Boolean> r3 = ser.submit(t3); //获取结果 Boolean rs1 = r1.get(); Boolean rs2 = r2.get(); Boolean rs3 = r3.get(); //关闭服务 ser.shutdown(); } } //下载器 class WebDownloader { //下载方法 public void downloader(String url, String name){ //下载器 try { //文件单元.复制URL文件 // 把一个url变成一个文件 FileUtils.copyURLToFile( new URL(url), new File(name)); } catch (IOException e) { e.printStackTrace(); System.out.println("IO异常,downloader方法出现问题"); } } } 下载了文件名为:2.jpg 下载了文件名为:1.jpg 下载了文件名为:3.jpg
多个线程同时操作一个对象,如:取钱、买火车票
初识并发问题
package com.y.demo01; //多个线程同时操作同一个对象 //买火车票 //发现问题: 多个线程操作同一个资源的情况下, 线程不安全, 数据紊乱 public class TestThread4 implements Runnable{ //票数 ticketNums 票券 private int ticketNums = 10;//ticketNums 票券 @Override public void run() { while (true) { if (ticketNums <= 0) { break; } try { //模拟 延迟 Thread.sleep(200); //毫秒 } catch (InterruptedException e) { e.printStackTrace(); } // Thread.currentThread().getName():获得当前执行线程的名字 System.out.println(Thread.currentThread().getName() + " -->拿到了第"+ ticketNums-- +"票"); } } public static void main(String[] args) { TestThread4 ticket = new TestThread4(); // 票 //线程 线程名 Thread thread = new Thread(ticket,"黄牛党"); thread.start(); // 简化 new Thread(ticket,"小明").start(); new Thread(ticket,"老师").start(); } } 小明 -->拿到了第10票 黄牛党 -->拿到了第10票 老师 -->拿到了第9票 小明 -->拿到了第8票 黄牛党 -->拿到了第6票 老师 -->拿到了第7票 老师 -->拿到了第5票 黄牛党 -->拿到了第5票 小明 -->拿到了第5票 老师 -->拿到了第4票 黄牛党 -->拿到了第4票 小明 -->拿到了第4票 小明 -->拿到了第2票 黄牛党 -->拿到了第1票 老师 -->拿到了第3票
案例:龟兔赛跑
1.首先来个赛道距离,然后要离终点越来越近 , for循环判断了100步
2.判断比赛是否结束 ,gameOver() 方法
3.打印出胜利者
4.龟兔赛跑开始
5.故事中是乌龟赢了,兔子需要睡觉,所以我们模拟兔子睡觉
6.终于,乌龟赢了
package com.y.demo01;
//Race:比赛
// 模拟 龟兔赛跑
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(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判断比赛是否结束
boolean flag = gameOver(i);
//如果比赛结束了,停止程序
if (flag){ // 默认为 true
break;
}
//线程的名字
System.out.println(Thread.currentThread().getName()+ "跑了" +i+ "步");
}
}
//判断是否完成比赛
private boolean gameOver (int steps){ //游戏结束
//判断是否有胜利者
if (winner != null){ // 已经存在胜利者了
return true;
}
else if (steps >= 100) {
winner = Thread.currentThread().getName();//线程名字 赋值给 winner
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();
}
}
静态代理
静态代理总结:
1. 真实对象和代理对象都要实现同一个接口
2. 代理对象 要代理 真实角色
好处:
代理对象 可以做很多对象做不了的事情
真实对象 专注做自己的事情
package com.y.staticProxy;
//静态代理
/*
静态代理模式总结
真实对象或目标对象 和 代理对象都要实现同一个接口
代理对象要 代理 真实角色
*/
/*
好处:
代理对象 可以做很多 真实对象 做不了的事情
真实对象 专注做自己的事情
*/
public class StaticProxy {
public static void main(String[] args) {
You you = new You();// 你要结婚
//多线程开启
Thread thread = new Thread( );
thread.start();
//简化
new Thread().start();
//Runnable:接口 Thread类也实现了Runnable接口
new Thread(new Runnable() {
@Override
public void run() {
}
}).start();
//lambda 表达式简化
new Thread( () -> System.out.println("ai")).start();
new Thread( ()-> System.out.println("我爱你") ).start();
/*WeddingCompany weddingCompany = new WeddingCompany( you );
weddingCompany.HappyMarry();*/
//简化
new WeddingCompany( new You()).HappyMarry();
}
}
//共同接口 结婚
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 before() {
System.out.println("结婚之前,布置现场");
}
//结婚之后
private void after() {
System.out.println("结婚之后,收尾款");
}
}
Lambda表达式
入 希腊字母表中排序第十一位的字母,英语名称为Lambda
避免内部类定义过多
其实质属于函数式编程概念
(params) -> expression [表达式]
(params) -> statement [语句]
(params) -> {statement }
123
new Thread(()-> System.out.println("多线程学习")).start();
1
为什么要使用lambda 表达式
1.避免你们内部类定义过多
2.可以让你的代码看起来很简洁
3.去掉了一堆没有意义的代码,只留下核心的逻辑
函数式接口
-
理解Functional lnterface(函数式接口)是学习Java8 lambda表达式的关键所在。
-
函数式接口的定义
1.任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口。
2.对于函数式接口,我们可以通过lambda 表达式来创建该接口的对象。
public interface Runnable{ //多线程接口
public abstract void run();//抽象方法
}
代码实现
package com.y.lambda;
/*
推到 lambda表达式
*/
public class TestLambda1 {
//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");
}
}
I like lambda
I like lambda2
I like lambda3
I like lambda4
I like lambda5
简化
package com.y.lambda;
public class TestLambda2 {
public static void main(String[] args) {
ILove love = null;
/*love = (int a,int b,int c) -> {
System.out.println("i love you -->" +a);
System.out.println("i love you -->" +b);
};*/
//简化1 去掉参数类型
love=(a,b,c) ->{
System.out.println("i love you -->" +a);
System.out.println("i love you -->" +b);
};
//简化2 去掉括号 :单个参数才可以去掉括号!
/* love= a -> {
System.out.println("i love you -->" +a);
};*/
//简化3 去掉花括号
love = (a,b,c) -> System.out.println("i love you -->" +a);
/**
* 总结
* lambda表达式只能有一行代码的情况下才能简化成为一行,如果有多行,用代码块包裹
* 前提是接口为函数式接口 函数式接口:只能有一个方法的接口是函数式接口
* 多个参数 可以去掉参数类型,要去掉就都去掉,必须加上括号!
*/
love.love(521,2,3);
}
}
//定义一个函数式接口
interface ILove{
void love(int a, int b, int c);
}
i love you -->521