写点什么

Java 线程讲解,这次没有人学不会了吧!!!

用户头像
霖~
关注
发布于: 2021 年 04 月 12 日
Java线程讲解,这次没有人学不会了吧!!!

前言

不知道你们有没有想过,我们在打王者荣耀的时候,为什么可以那么多人同时一起打,可以相互能看到而互不影响,这个就和多线程有关,今天我们来学习线程。

线程

运行中的应用程序称为“进程”,进程中能够独立执行的控制流称为“线程”,一个进程可由多个线程组成,它们分别执行不同的任务,例如视频中同时可以听声音、看图像、看弹幕等。

  • 进程是执行程序的一次执行过程,是动态的概念,是系统资源分配的单位;

  • 线程是 CPU 调度和执行的单位,是独立的执行路径,一个进程中至少有一个线程,不然就没存在的意义。

注意:

  • 真正的多线程是指有多个 CPU,也就是多核,很多多线程是模拟出来的。

  • 线程的运行由调度器安排调度,调度器是与操作系统相关的,先后顺序是不能人为的干预;

  • 线程会带来额外的开销,每个线程在自己的工作内存交互,内存控制不当会造成数据不一致;

线程的创建与启动

当用 Java 命令启动一个 JVM 进程时,JVM 会创建一个主线程,该线程从程序入口(main()方法)开始运行。

线程的创建有三种方式:继承 Thread 类、实现 Runnable 接口和实现 Callable 接口(简单了解)

其中 Thread 类的主要方法有:

  • start():启动线程;

  • currentThread():返回当前运行的 Thread 对象;

  • run():由调度程序调用,当 run()方法返回时,该线程停止;

  • sleep(int n):使线程睡眠 n 毫秒后,线程再次运行;

  • setPriority(int p):设置线程优先级;

  • getPriority():返回线程优先级;

  • yield():将 CPU 控制权主动移交到下一个可运行线程;

  • setName(String name):赋予线程一个名字;

  • getName():取得代表线程名字的字符串;

  • stop():停止线程的执行。

继承 java.lang.Thread 类

用户可以创建 Thread 类的实例来创建新的线程,它将与主线程并发运行。子类继承 Thread 类具备多线程能力,通过调用用户线程类的 start()方法即可启动用户线程。

创建步骤:

  1. 声明一个类并继承 Thread 类;

  2. 重写 run()方法,编写线程执行体;

  3. 创建线程对象并调用 start()方法启动线程。

例如:

public class first {  static class Threadcase extends Thread{    //创建Threadcase类并继承Thread    public void run() {               //重写run()方法      System.out.println("欢迎学习Java线程!!!");    }  }  public static void main(String[] args)throws Exception {    Threadcase t=new Threadcase();      //创建Threadcase类实例对象    t.start();                //调用start()方法启动线程        System.out.println("我是主线程");    }}
复制代码

运行结果为:

我是主线程欢迎学习Java线程!!!
复制代码

注意:

  • 多次运行上述代码会发现,运行结果会不一样;

  • 当运行的线程执行体很多时,会发现主线程和子线程会交替执行;

  • 假如将 start()方法改为 run()方法,会根据代码顺序来执行,大家可以自行尝试试试。

实现 Runnable 接口

由于 Java 的单继承限制,有些类必须继承其他某个类同时又要实现线程的特性,这时可以通过实现接口 Runnable 来解决该问题。该接口具有多线程能力,启动线程为传入目标对象+Thread 对象.start()。创建一个线程来声明实现类 Runnable 接口,然后重写 run 方法。然后可分配类的实例,在创建 Thread 时作为参数传递并启动。

创建步骤:

  1. 定义类实现 Runnable 接口;

  2. 重写 run()方法,编写线程执行体;

  3. 创建线程对象;

  4. 创建 Thread 作为参数传递,调用 start()方法启动线程。

例如:

public class first {  static class Threadcase implements Runnable{        //创建一个Threadcase类并实现Runnable接口    public void run() {                  //重写run()方法      System.out.println("欢迎学习Java线程!!!");    }  }  public static void main(String[] args)throws Exception {       Threadcase t=new Threadcase();             //创建实现类对象    Thread thread=new Thread(t);             //创建代理类对象    thread.start();                      //启动线程  }}
复制代码

运行结果为:

欢迎学习Java线程!!!
复制代码

注意:第 9、10 行代码可以改为:

new Thread(t).start();
复制代码

实现 Callable 接口

由于 Callable 接口使用的很少,我们这里只做简单地了解该实现步骤,感兴趣的同学可以自行去编写代码实现。创建步骤:

  1. 实现 Callable 接口,需要返回值类型;

  2. 重写 call 方法,需要抛出异常;

  3. 创建目标对象;

  4. 创建执行服务:ExecutorService ser=Executors.newFixedThreadPool(1);

  5. 提交执行:Future<Boolean>result1=ser.submit(t1);

  6. 获取结果:boolean r1=result.get();

  7. 关闭服务器:ser.shutdownNow();

静态代理

代理这个词大家都不陌生吧,就是我帮你去做一件事情。例如我们在打王者荣耀的时候,有时会请别人帮自己上分,最后真正上分的账号是自己的账号。这种属于代理。

  • 自己:属于真实角色;

  • 代理角色:代理你,帮自己上分;

  • 上分:实现都实现上分接口即可。

例如:

public class first {  public static void main(String[] args){    GameLeveing gameleveing=new GameLeveing(new My());    //创建GameLeveing类实例对象并使用My类    gameleveing.agency();                  //调用agency方法  }}interface Points{  void agency();}class My implements Points{          //创建My类实现Points接口(真实对象,我自己的账号要上荣耀王者)  public void agency() {          //重写agency()方法    System.out.println("我上荣耀王者啦");  }}class GameLeveing implements Points{     //创建GameLeveing类实现Points接口(代理对象,帮助自己上分)  private Points target;          //关键字target目标  public GameLeveing(Points target) {     //传递真实对象,使真实对象可以调用代理对象的方法    this.target=target;            }  public void agency() {          //重写agency方法    before();    this.target.agency();        //真实对象    after();  }  private void before() {          //创建私有方法before和after    System.out.println("上分之前,登录账号,玩游戏");  }  private void after() {    System.out.println("上分之后,收尾款");  }}
复制代码

运行结果为:

上分之前,登录账号,玩游戏我上荣耀王者啦上分之后,收尾款
复制代码

注意:真实对象和代理对象都要实现同一个接口,代理对象要代理真实对象。

代理的好处:代理对象可以做很多真实对象做不了的事情,真实对象可以专注做自己的事情。

Lambda 表达式

为了避免匿名内部类定义过多,去掉了一些没有意义的代码,只留下核心的逻辑,让我们的代码看起来很简洁,我们可以使用 lambda 表达式。

注意:

  • lambda 表达式只能有一行代码的情况下才能简化成为一行,如果有多行,那么就用代码块包裹;

  • 使用 Lambda 表达式的前提是接口为函数式接口。

函数式接口

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

interface like{  void lambad();}
复制代码

对于函数式接口,我们可以通过 Lambda 表达式来创建该接口的对象。

like l=()->{      System.out.println("lkl");    };l.lambda();
复制代码

这样讲可能大家理解不了使用 Lambda 表达式的好处,我们现在通过两个例子来理解一下。

例子一:没有使用 Lambda 表达式

public class first {  public static void main(String[] args){    nonuse no=new nonuse();    no.lambda(5);  }}interface like{  void lambda(int a);}class nonuse implements like{  public void lambda(int a) {    System.out.print(a);  }}
复制代码

例子二:使用 Lambda 表达式

public class first {  public static void main(String[] args){    like l=(int a)->{System.out.println(a);};    l.lambda(5);  }}interface like{  void lambda(int a);}
复制代码

上面两个例子的代码的运行结果都一样,运行结果为:

5
复制代码

Lambda 表达式可以继续简化,例子二中第 3 行代码可以简化为:

   like l=(a)->{System.out.println(a);};或 like l=a->{System.out.println(a);};或 like l=a->System.out.println(a);;
复制代码

其运行结果不变。

注意:当有多个参数时,也可以去掉参数类型,但要所有参数类型都要去掉,参数必须要用括号括起来。

最后

好了,有关线程的一些知识讲到这里,谢谢观看!!!

下篇继续讲解线程的其他知识(线程的状态,线程的同步问题等等)

成功不是将来才有的,而是从决定去做的那一刻起,持续累积而成。

发布于: 2021 年 04 月 12 日阅读数: 63
用户头像

霖~

关注

还未添加个人签名 2021.04.11 加入

还未添加个人简介

评论

发布
暂无评论
Java线程讲解,这次没有人学不会了吧!!!