前言:

本文内容:实现Callable接口、静态代理模式、Lambda表达式、线程停止、线程休眠sleep、线程礼让yield、线程强制执行join

推荐免费Java多线程讲解视频:【狂神说Java】多线程详解_哔哩哔哩_bilibili

实现Callable接口(仅作了解)

  1. 实现Callable接口,需要返回值类型;
  2. 重写call方法,需要抛出异常;
  3. 创建目标对象;
  4. 创建执行服务:ExecutorService service = Executors.newFixedThreadPool(创建线程数量);
  5. 提交执行:Future<Boolean> result1 = service.submit(t1);
  6. 获取结果:boolean r1 = result1.get();
  7. 关闭服务:service.shutdownNow();
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
62
63
64
65
66
package com.jokerdig.demo2;

import com.jokerdig.demo1.TestThread2;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

/**
* @author Joker大雄
* @data 2021/8/21 - 11:18
**/
//线程创建方式三:实现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;
}

@Override
public Boolean call() throws Exception {
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://cdn.jsdelivr.net/gh/JokerDaxiong/JokerDaxiong.github.io@main/images/avatar.png", "autor.png");
TestCallable t2 = new TestCallable("https://cdn.jsdelivr.net/gh/JokerDaxiong/JokerDaxiong.github.io@main/images/avatar.png", "autor1.png");
TestCallable t3 = new TestCallable("https://cdn.jsdelivr.net/gh/JokerDaxiong/JokerDaxiong.github.io@main/images/avatar.png", "autor2.png");

// 1. 创建执行服务:
ExecutorService service = Executors.newFixedThreadPool(3);
// 2. 提交执行:
Future<Boolean> result1 = service.submit(t1);
Future<Boolean> result2 = service.submit(t2);
Future<Boolean> result3 = service.submit(t3);
// 3. 获取结果:
boolean r1 = result1.get();
boolean r2 = result2.get();
boolean r3 = result3.get();
// 4. 关闭服务:
service.shutdownNow();
}
}

//下载器
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异常");
}
}
}

静态代理模式

静态代理:(以结婚举例)

  • 你:真实角色
  • 婚庆公司:代理你,帮你处理结婚事务
  • 结婚:实现结婚接口即可

总结:

  • 真是对象和代理对象都要实现同一接口;
  • 代理对象要代理真实角色;

好处:

  • 代理对象可以做很多真实对象做不了的事情;

  • 真实对象专注做自己的事情;

    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 com.jokerdig.demo2;

    /**
    * @author Joker大雄
    * @data 2021/8/21 - 11:32
    **/
    public class StaticProxy {
    public static void main(String[] args) {
    WeddingCompany weddingCompany = new WeddingCompany(new You());
    weddingCompany.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;

  • 避免匿名内部类定义过多;

  • 其实质属于函数式编程的概念;

    1
    2
    3
    (params) -> expression[表达式]
    (params) -> statement[语句]
    (params) -> expression[表达式]

    a-> System.out.println("it's is lambda"+a);

    new Thread(()->System.out.println("多线程学习")).start();

  • 为什么要使用lambda表达式

    • 避免匿名内部类定义过到;
    • 让代码看起来更简介;
    • 去掉大量无意义代码,只留下核心的逻辑;
  • 也去你会说,我看了Lambda表达式,反而觉得更乱了,看不懂了。多用就能习惯了;

  • 理解Functional Interface(函数式接口)是学习Java8 lambda表达式的关键所在;

  • 函数时接口的定义:

    • 任何接口,如果只包含唯一一个抽象方法,那么他就是一个函数式接口;

      1
      2
      3
      public interface Runnable{
      public abstract void run();
      }
    • 对于函数式接口,我们可以通过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
    58
    59
    60
    61
    62
    63
    package com.jokerdig.lambda;

    /**
    * @author Joker大雄
    * @data 2021/8/21 - 12:52
    **/
    //lambda表达式
    public class Test1 {
    //3.静态内部类
    static class Like2 implements Likes{

    @Override
    public void lambda() {
    System.out.println("I like lambda2");
    }
    }
    public static void main(String[] args) {

    Likes like = new Like();
    like.lambda();
    like = new Like2();
    like.lambda();

    //4.局部内部类
    class Like3 implements Likes{

    @Override
    public void lambda() {
    System.out.println("I like lambda3");
    }
    }
    //调用
    new Like3().lambda();

    //5.匿名内部类
    like = new Likes(){

    @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 Likes{
    void lambda();
    }
    //2.实现类
    class Like implements Likes{

    @Override
    public void lambda() {
    System.out.println("I like 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
    package com.jokerdig.lambda;

    /**
    * @author Joker大雄
    * @data 2021/8/21 - 13:14
    **/
    public class Test2 {

    public static void main(String[] args) {
    //lambda表达式简化
    ILove love =(int a)->{
    System.out.println("I love you"+a);
    };
    love.love(1);
    //1.简化参数类型
    love =(a)->{
    System.out.println("I love you"+a);
    };
    love.love(2);
    //2.简化括号
    love = a ->{
    System.out.println("I love you"+a);
    };
    love.love(3);
    //3.简化大括号
    love = a -> System.out.println("I love you"+a);;
    love.love(4);

    }
    }
    interface ILove{
    void love(int a);
    }

总结:

  • lambda表达式只有一行代码的情况下才能简化成一行的形式,如果有多行,那么就用代码块包裹。
  • 前提是接口位函数式接口。
  • 多个参数也可以去掉参数类型,要去掉必须加括号。

线程停止

线程状态:

fv8A2j.png

fv85WQ.md.png

线程方法:

方法 说明
setPriority(int newPriority) 更改线程的优先级
static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠
void join() 等待该线程终止
static void yield() 暂停当前正在执行的线程对象,并执行其他前程
void interrupt() 中断线程,尽量不使用该方法
boolean isAlive() 测试线程是否处于活动状态

停止线程:

  • 不推荐使用JDK提懂得stop(),destroy()方法。(已废弃)

  • 推荐线程自己停止下来。

  • 建议使用一个标志位进行终止变量,当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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    package com.jokerdig.state;

    /**
    * @author Joker大雄
    * @data 2021/8/21 - 13:48
    **/
    //测试stop
    //1.建议线程正常停止
    //2.建议使用标志位
    //3.不要使用stop或者destroy等过时方法
    public class TestStop implements Runnable{

    //设置标志位
    private boolean flag=true;

    @Override
    public void run() {
    int i=0;
    while (flag){
    System.out.println("run...Thread"+i++);
    }
    }
    //设置一个公开的方法停止线程,转换标志位
    public void stop(){
    this.flag = false;
    }


    public static void main(String[] args) {
    TestStop testStop = new TestStop();
    new Thread(testStop).start();

    for (int i = 0; i < 1000; i++) {
    System.out.println("run"+i);
    if(i==900){
    testStop.stop();
    System.out.println(i+"停止线程");
    }
    }

    }
    }

线程休眠sleep

线程休眠:

  • sleep(时间)指定当前线程阻塞的毫秒数;
  • sleep存在异常interruptedException;
  • sleep时间达到后线程进入就绪状态;
  • sleep可以模拟网络延时,倒计时等;
  • 每一个对象都有一个锁,sleep不会释放锁;

模拟倒计时:

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
package com.jokerdig.state;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
* @author Joker大雄
* @data 2021/8/21 - 14:02
**/
//模拟倒计时
public class TestSleep2 {
public static void main(String[] args) {
//模拟倒计时
try {
tenDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
//打印当前系统时间
Date startTime = new Date(System.currentTimeMillis());//获得当前时间

try {
while(true){
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
startTime = new Date(System.currentTimeMillis());//更新时间
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//模拟倒计时
public static void tenDown() throws InterruptedException{
int num =10;
while (true){
Thread.sleep(1000);
System.out.println(num--);
if(num<=0){
System.out.println("时间结束");
break;
}
}
}
}

线程礼让yield

线程礼让:

  • 礼让线程,让当前正在执行的线程暂停,但不阻塞;

  • 将线程从运行状态转为就绪状态;

  • 让CPU重新调度,礼让不一定成功!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package com.jokerdig.state;

    /**
    * @author Joker大雄
    * @data 2021/8/21 - 14:17
    **/
    //礼让线程,不一定成功
    public class TestYield {
    public static void main(String[] args) {
    MyYield myYield = new MyYield();
    new Thread(myYield,"a").start();
    new Thread(myYield,"b").start();
    }
    }
    class MyYield implements Runnable{

    @Override
    public void run() {
    System.out.println(Thread.currentThread().getName()+"线程开始执行");
    Thread.yield();//礼让
    System.out.println(Thread.currentThread().getName()+"线程停止执行");
    }
    }

线程强制执行join

  • Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞;

  • 可以想象成插队;

    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
    package com.jokerdig.state;

    /**
    * @author Joker大雄
    * @data 2021/8/21 - 14:23
    **/
    //测试Join方法
    public class TestJoin implements Runnable{

    public static void main(String[] args) throws InterruptedException {
    TestJoin testJoin = new TestJoin();
    Thread thread = new Thread(testJoin);

    //主线程
    for (int i = 1; i < 200; i++) {
    if(i==100){
    //start放这里防止vip线程提前同普通线程一起启动
    thread.start();
    thread.join();//插队
    }
    System.out.println("普通线程"+i);
    }
    }
    //插队
    @Override
    public void run() {
    for (int i = 1; i < 500; i++) {
    System.out.println("线程vip来了"+i);
    }
    }
    }