多线程实现,并发,静态代{过}{滤}理以及lambda表达式的推演知识详解
本帖最后由 黑白客 于 2021-2-26 15:36 编辑java多线程
线程简介
线程实现
初识并发问题
实现Callable接口
静态代{过}{滤}理
Lambda表达式
java多线程
## 线程简介
多线程:比如我们可以在电脑上一边听音乐,一边浏览网页等等。
- 核心概念
- 程序是静态的,一个程序跑起来之后就会变成一个进程,一个进程里可以有多个线程。main方法是主线程
- 线程就是独立的执行路径
- 在程序运行时,即使自己没有创建线程,后台也会有多个线程,如:主线程,gc线程(垃圾回收机制)
- main方法为主线程,为系统的入口,用于执行整个程序。
- 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度。调度器是与电脑操作系统紧密相关的,先后顺序是不能人为干预的。
- 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制。
- 线程会带来额外的开销,如cpu调度时间,并发控制开销。
- 每个线程在自己工作内存交互,内存控制不当会造成数据不一致
## 线程实现
- 方法一
- 创建一个类,继承Thread类。实现其run()方法、run方法就是线程体
- 在main方法中创建类的对象,调用start()方法。实现多线程。如果调用run方法,就不会实现多线程。是单线程。
- 线程创建之后并不会立即执行,需要cpu的调度安排。cpu在同一时间只能调用一个线程。
网图下载:利用多线程,下载多个网图
```java
package com.wang.threadDemo;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
/**
* @author: 王海新
* @Date: 2021/2/22 11:24
* @Description:下载网图
*/
public class TestThread2 extends Thread {
private String url;
private String name;
TestThread2(String url,String name){
this.url = url;
this.name = name;
}
@Override
public void run() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.download(url,name);
System.out.println("文件被下载了" + name);
}
public static void main(String[] args) {
TestThread2 test1 = new TestThread2("https://ss1.baidu.com/9vo3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/cdbf6c81800a19d86524639732fa828ba61e4679.jpg", "1.jpg");
TestThread2 test2 = new TestThread2("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.08087.cc%2Fuploads%2F20191221%2F19%2F1576927577-ezdtLhXcng.jpg&refer=http%3A%2F%2Fimg.08087.cc&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616557755&t=9c5d0cdc0fd6d2988b9522d0dab2f9c7", "2.jpg");
TestThread2 test3 = new TestThread2("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.08087.cc%2Fuploads%2F20190819%2F10%2F1566182328-nwMPsxzGXL.jpg&refer=http%3A%2F%2Fimg.08087.cc&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616557823&t=e0da3b689853d27b1a26d2879faec7eb", "3.jpg");
test1.start();
test2.start();
test3.start();
}
}
/*********************************************************************************************************************
* @Author:王海新
* @Date:11:262021/2/22
* @Version:1.0.0
* @Description:下载器
*/
classWebDownloader{
//下载方法
public void download(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
System.out.println("io出错,出错方法:WebDownload");
}
}
}
```
- 第二种方法:实现Runable接口,推荐使用 避免单线程的局限性。
```java
package com.wang.threadDemo;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
/**
* @author: 王海新
* @Date: 2021/2/22 16:36
* @Description: 实现Runnable接口
*
*/
public class TestThread3 implements Runnable {
private String url;
private String name;
TestThread3(String url,String name){
this.url = url;
this.name = name;
}
@Override
public void run() {
WebDownloader1 webDownloader = new WebDownloader1();
webDownloader.download1(url,name);
System.out.println("文件被下载了" + name);
}
public static void main(String[] args) {
TestThread3 test1 = new TestThread3(
"https://ss1.baidu.com/9vo3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/cdbf6c81800a19d86524639732fa828ba61e4679.jpg", "4.jpg");
TestThread3 test2 = new TestThread3(
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.08087.cc%2Fuploads%2F20191221%2F19%2F1576927577-ezdtLhXcng.jpg&refer=http%3A%2F%2Fimg.08087.cc&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616557755&t=9c5d0cdc0fd6d2988b9522d0dab2f9c7", "5.jpg");
TestThread3 test3 = new TestThread3(
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.08087.cc%2Fuploads%2F20190819%2F10%2F1566182328-nwMPsxzGXL.jpg&refer=http%3A%2F%2Fimg.08087.cc&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616557823&t=e0da3b689853d27b1a26d2879faec7eb", "6.jpg");
new Thread(test1).start();
new Thread(test2).start();
new Thread(test3).start();
}
}
/*********************************************************************************************************************
* @Author:王海新
* @Date:11:262021/2/22
* @Version:1.0.0
* @Description:下载器
*/
classWebDownloader1 {
//下载方法
public void download1(String url, String name) {
try {
FileUtils.copyURLToFile(new URL(url), new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("io出错,出错方法:WebDownload1");
}
}
}
```
基本上和继承Thread类相同,只是在调用的时候。
new 实现类
new Thread(实现类名).start();来调用
## 初识并发问题
通过以下程序,可以发现在抢票的过程中,多个线程操作
同一个资源,会出现错误
```java
package com.wang.threadDemo;
/**
* @author: 王海新
* @Date: 2021/2/22 17:07
* @Description: 多个线程同时操作一个对象
* 买火车票的例子
*
* 发现问题:多个线程操作同一个资源的情况下,不安全
*/
public class TestThread4 implements Runnable{
private int ticketNumbel = 10; //火车票
@Override
public void run() {
while (true){
if (ticketNumbel <= 0) {
break;
}
//添加延迟
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 拿到了第" + ticketNumbel-- + "张票");
}
}
public static void main(String[] args) {
TestThread4 ticket = new TestThread4();
new Thread(ticket,"小明").start();
new Thread(ticket,"老师").start();
new Thread(ticket,"黄牛党").start();
new Thread(ticket,"键盘侠").start();
}
}
```
利用以下龟兔赛跑的案例,来巩固一下多线程的概念
```java
package com.wang.threadDemo;
/**
* @author: 王海新
* @Date: 2021/2/22 17:26
* @Description: 龟兔赛跑
*
*/
public class Race implements Runnable {
privatestatic String winner;//胜利者
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
//模拟兔子睡觉
if (Thread.currentThread().getName().equals("兔子") && i == 90) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "--> 跑了 " + i +"步");
//判断是否跑完一百步
if (gameOver(i)) {
break;
}
}
}
/*********************************************************************************************************************
* @Author:王海新
* @Date:17:342021/2/22
* @Version:1.0.0
* @Description:判断是否结束比赛
*/
private boolean gameOver(int steps){
//判断是否存在胜利者
if (winner != null) {//已经存在获胜者
return true;
}
if (steps >= 100) {
winner = Thread.currentThread().getName();
System.out.println( winner + "获胜");
return true;
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race,"乌龟").start();
new Thread(race,"兔子").start();
}
}
```
## 实现Callable接口
```java
package com.wang.threadDemo;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
/**
* @author: 王海新
* @Date: 2021/2/25 19:18
* @Description:线程创建方式三:实现callable接口
* 可以获取一个返回值
* 可以抛出异常
* 但是需要创建一个服务,通过服务提交
*/
public class TestCallable implements Callable<Boolean> {
private String url;
private String name;
TestCallable(String url,String name){
this.url = url;
this.name = name;
}
@Override
public Boolean call() {
WebDownloader3 webDownloader = new WebDownloader3();
webDownloader.download1(url,name);
System.out.println("文件被下载了" + name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable test1 = new TestCallable(
"https://ss1.baidu.com/9vo3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/cdbf6c81800a19d86524639732fa828ba61e4679.jpg", "4.jpg");
TestCallable test2 = new TestCallable(
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.08087.cc%2Fuploads%2F20191221%2F19%2F1576927577-ezdtLhXcng.jpg&refer=http%3A%2F%2Fimg.08087.cc&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616557755&t=9c5d0cdc0fd6d2988b9522d0dab2f9c7", "5.jpg");
TestCallable test3 = new TestCallable(
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.08087.cc%2Fuploads%2F20190819%2F10%2F1566182328-nwMPsxzGXL.jpg&refer=http%3A%2F%2Fimg.08087.cc&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616557823&t=e0da3b689853d27b1a26d2879faec7eb", "6.jpg");
//1 创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(3);
//2 提交执行
Future<Boolean> s1 = ser.submit(test1);
Future<Boolean> s2 = ser.submit(test2);
Future<Boolean> s3 = ser.submit(test3);
//3 获取结果
boolean q = s1.get();
boolean q1 = s2.get();
boolean q2 = s3.get();
//4 关闭服务
ser.shutdown();
}
}
/*********************************************************************************************************************
* @Author:王海新
* @Date:19:212021/2/25
* @Version:1.0.0
* @Description:下载器
*/
classWebDownloader3 {
//下载方法
public void download1(String url, String name) {
try {
FileUtils.copyURLToFile(new URL(url), new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("io出错,出错方法:WebDownload1");
}
}
}
```
## 静态代{过}{滤}理
看一个结婚的案例
```java
package com.wang.threadDemo1;
/**
* @author: 王海新
* @Date: 2021/2/26 09:49
* @Description: 静态代{过}{滤}理模式总结
* 真实对象和代{过}{滤}理对象都要实现同一个接口
* 代{过}{滤}理对象要代{过}{滤}理真实角色
*
* 好处:
*代{过}{滤}理对象可以做很多真实对象做不了的事情
*真实对象专注做自己的事情
*/
public class StacticProxy {
public static void main(String[] args) {
WeddingCompany weddingCompany = new WeddingCompany(new You());
weddingCompany.HappyMarry();
//还可以简写为一行代码
// new WeddingCompany(new You()).HappyMarry();
}
}
//结婚的接口
interface Marry{
/*********************************************************************************************************************
* @Author:王海新
* @Date:9:532021/2/26
* @Version:1.0.0
* @Description: 开心的结婚
* 人间四大喜事
* * 久旱逢甘露
* * 他乡遇故知
* * 洞房花烛夜
* * 金榜题名时
*/
void HappyMarry();
}
/*********************************************************************************************************************
* @Author:王海新
* @Date:9:542021/2/26
* @Version:1.0.0
* @Description:真实角色,你去结婚
*/
class You implements Marry{
@Override
public void HappyMarry() {
System.out.println("我要结婚啦");
}
}
/*********************************************************************************************************************
* @Author:王海新
* @Date:9:552021/2/26
* @Version:1.0.0
* @Description:代{过}{滤}理角色,帮助你结婚
* 他会在你原来实现功能之前之后添加新的东西
*/
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("结婚前,布置现场");
}
}
```
## Lambda表达式
理解函数式接口是学习Lamda表达式的关键所在
- Lamda函数式接口的定义:
- 任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口。
- 对于函数式接口,就可以通过lambda表达式来创建接口
- lambda推演过程
```java
package com.wang.threadDemo1;
/**
* @author: 王海新
* @Date: 2021/2/26 11:00
* @Description: 推演lambda表达式
*/
public class lambda {
//2.定义一个静态内部类,实现
static class Like2 implements Ilike{
@Override
public void lambda() {
System.out.println(2);
}
}
public static void main(String[] args) {
//1.创建外部类对象实现
Ilike like = new Like();
like.lambda();
Like2 likeq = new Like2();
likeq.lambda();
//3.定义一个局部内部类实现
class Like3 implements Ilike{
@Override
public void lambda() {
System.out.println(3);
}
}
Like3 like1 = new Like3();
like1.lambda();
//4.匿名内部类,没有类的名称,必须借助类的接口或者父类
like = new Ilike(){
@Override
public void lambda() {
System.out.println(4);
}
};
like.lambda();
//5.使用lambda简化
like = () -> {
System.out.println("5");
};
like.lambda();
}
}
//定义一个函数式接口
interface Ilike{
void lambda();
}
//定义一个实现类
class Like implements Ilike{
@Override
public void lambda() {
System.out.println(1);
}
}
```
- lambda表达式简化
```java
package com.wang.threadDemo1.lambda;
/**
* @author: 王海新
* @Date: 2021/2/26 11:33
* @Description: 函数式接口的有参方法 简化
* 多个参数也可以去掉参数类型,但是要去掉都去掉。必须加上括号
*/
public class lambda2 {
public static void main(String[] args) {
//1
Iove iove = (int a) ->{
System.out.println("爱你"+a);
};
iove.honey(111);
//2 去掉形参的参数类型
Iove iove1 = (a) ->{
System.out.println("爱你"+a);
};
iove1.honey(222);
//3 去掉括号(无参方法不可以去掉
Iove iove2 = a ->{
System.out.println("爱你"+a);
};
iove2.honey(333);
//4 去掉大括号(假如你的代码有多行,就不可以去掉大括号,因为一个分号就表示结束了。没办法添加新的一行
Iove iove3 = a ->System.out.println("爱你"+a);
iove3.honey(444);
}
}
interface Iove{
void honey(int a);
}
``` 楼主头像好评 皮卡丘很好看,真不错 有头像妹子的 种子吗 求分享 java的函数式编程让人心累 nj001 发表于 2021-2-26 23:07
java的函数式编程让人心累
嗯?是吗?
页:
[1]