【Java多线程讲解-上】搞懂多线程看这一篇就够了

前言:在当今的互联网行业中,多线程技术已经成为了一项非常重要的技能。随着计算机硬件的发展,越来越多的程序员开始关注多线程技术,希望通过多线程来提高程序的性能。Java作为一种广泛使用的编程语言,也提供了丰富的多线程支持。本文将详细介绍Java多线程的基本概念、原理、实现方法以及在生活中的应用,帮助读者更好地理解和掌握Java多线程技术。

在这里插入图片描述

多线程简介

假设你正在厨房做饭,而你需要同时炒两个不同的菜。在这个场景中,你可以认为你自己就是一个线程,而这两个菜分别代表另外两个线程。

当你炒第一个菜时,你需要先切好菜,然后放在锅里热油,接着把菜倒入锅中翻炒。这是一个典型的串行过程,因为每一步都必须按照顺序进行。但是,当你炒第二个菜时,如果你仍然按照这种方式来做,那么你需要等待第一个菜完成所有的步骤后才能开始第二个菜。这样显然是低效的。

在这种情况下,利用多线程就可以提高效率。你可以在炒第一个菜的同时,提前准备好第二个菜所需要的材料。当第一个菜还在锅中翻炒的时候,你就可以开始处理第二个菜,比如切菜、热油等。这样一来,就可以节省很多时间。

同样的道理也适用于编程。在单线程的情况下,如果程序中包含多个任务,那么必须等到一个任务完成后才能开始下一个任务。而在多线程的情况下,我们可以将不同的任务分配给不同的线程,使得它们可以同时运行。这样可以显著提高程序的效率。在这里插入图片描述

线程的创建

1.继承Thread类,重写run()方法;

先创建一个类继承Thread类,并重写run()方法,run方法里面写这个线程要执行的代码

class thread extends Thread{
    
    
    @Override
   public void run(){
    
    
        //thread.currentThread().getName()得到当前线程的名字
        System.out.println("线程启"+thread.currentThread().getName()+"动了");
    }
}

然后创建对象,调用start方法启动线程

  public static void main(String[] args) {
    
    
        thread thread = new thread();
        thread.start();
    }

运行结果
请添加图片描述

实现Runnable接口,实现run()方法。

先创建一个类实现Runnable接口,再实现run()方法。

class thread1 implements Runnable{
    
    
    public void run(){
    
    
        System.out.println("线程启"+thread.currentThread().getName()+"动了");
    }
}

再创建一个Thread对象并将已经实现Runnable接口的对象作为参数传入。同样通过start方法启动线程

  Thread thread1 = new Thread(new thread1());
        thread1.start();

注意 两种方法都不要直接通过run方法启动线程,因为直接调用run方法程序只会在同一个线程执行任务——不会新创建一个线程;其实调用start方法的时候,会先创建一个线程再执行run方法

比较

建议大家用第二种,还是举做饭的例子:假如你现在要做连个菜,一个是炒菜、一个是披萨。如果用第一种方式,你要分别创建两个类来继承Thread。

public class Main {
    
    

    public static void main(String[] args) {
    
    
        CookFriedRice cookFriedRice = new CookFriedRice();
        CookPizza cookPizza = new CookPizza();
        cookFriedRice.start();
        cookPizza.start();


    }

}

class CookFriedRice extends Thread{
    
    
    @Override
   public void run(){
    
    
        System.out.println("开始炒菜了!!!");
    }
}
class CookPizza extends Thread{
    
    
    @Override
    public void run(){
    
    
        System.out.println("开始做披萨了!!!");
    }
}

如果采用实现Runnable接口来创建线程,那么我们只需要定义两个实现了Runnable接口的类,诶不是也要创建连个类吗???这里可用lambda表达式(不熟悉的朋友可以看这篇文章lambda表达式

public class Main {
    
    

    public static void main(String[] args) {
    
    

        new Thread(()-> System.out.println("开始炒菜了!!!")).start();
        new Thread(()-> System.out.println("开始做披萨了!!!")).start();

    }

}

代码是不是简洁了许多,并且不同的线程还可依操作同一个对象,实现信息共享

public class Main {
    
    

    public static void main(String[] args) {
    
    
        test test = new test();
        Thread thread1 = new Thread(test);
        Thread thread2 = new Thread(test);
        thread1.start();
        thread2.start();

    }

}

class test implements Runnable {
    
    
    private int count = 0;

    public void run() {
    
    
        count++;
        System.out.println(count);
    }
}

请添加图片描述

3.线程的状态

线程的状态与生命周期
Java中的线程有6种状态,分别是:新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、等待(Waiting)和终止(Terminated)。线程的生命周期包括以下几个阶段:新建、就绪、运行、阻塞、等待和终止。
在这里插入图片描述
我们还是通过做饭的例子来辅助理解:
在厨房里,厨师们正在准备一道菜,而每个厨师就像一个独立的任务处理器(也就是线程)。他们都有自己的任务列表,并且按照各自的顺序处理它们。
厨师的生命状态可以分为以下几个阶段:

新建状态 (New): 厨师被招聘进来并分配到相应的厨房区域进行工作。
就绪状态 (Runnable): 厨师准备好开始工作,等待主厨分配任务。
阻塞状态 (Blocked): 厨师被其他厨师暂时阻止了前进,例如在等用具清理完毕时。
运行状态 (Running): 厨师开始着手准备菜肴。
终止状态 (Terminated): 厨师完成了自己的任务并离开了厨房。

细节
其实一个线程调用start后,程序可能在远行也可能没有远行,这取决于系统分配给这个线程的时间(在Java规范中,没有将正在远行单独当作一个状态,一个正在运行的线程也有可能处于可远行状态),系统会为每个线程分配时间片,时间片用完了cpu就会将运行的机会给下一个线程,正是因为这个过程非常快,我们察觉不到切换的过程,以至于这些线程看起来都是同时运行。大家可以类比视频和一帧帧照片。
下面介绍几个方法
1.yield(静态方法)
当线程在运行时,将运行的机会让给别的线程(礼让),但礼让不一定成功,只是将运行权交给了cpu,让cpu重新调度
2. join
这个方法可以让注线程阻塞,等待子线程结束为止
看个例子

public class Main {
    
    

   public static void main(String[] args) throws InterruptedException {
    
    


       Thread thread1 = new Thread(()-> {
    
    
           for (int i = 0; i < 100; i++) {
    
    
               System.out.println(i+": 子线程在运行!!!");
           }
       });
       thread1.start();
       for (int i = 0; i <100 ; i++) {
    
    
           System.out.println(i+": 主线程在运行!!!");
       }




   }


运行结果
在这里插入图片描述
子线程和主线程并发运行

public class Main {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    


        Thread thread1 = new Thread(()-> {
    
    
            for (int i = 0; i < 100; i++) {
    
    
                System.out.println(i+": 子线程在运行!!!");
            }
        });
        thread1.start();
        for (int i = 0; i <100 ; i++) {
    
    

            if(i%2==0)
                thread1.join();
            System.out.println(i+": 主线程在运行!!!");
        }
        
    }

}

在这里插入图片描述
加了join后主线程等子线程结束后在运行。

本期内容就到这里,如果觉得写的不错的话可以关注下一期。
下期预告:

  • 线程同步与互斥
  • 线程间通信
  • 线程池的使用
  • Java多线程在生活中的应用

请添加图片描述

猜你喜欢

转载自blog.csdn.net/weixin_55939638/article/details/134574254