Java多线程详解(通俗易懂)

[复制链接]
发表于 2022-12-16 12:47:41 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
一、线程简介

1. 什么是进程?

电脑中会有很多单独运行的程序,每个程序有一个独立的进程,而进程之间是相互独立存在的。例如图中的微信、酷狗音乐、电脑管家等等。

2. 什么是线程?

进程想要执行任务就需要依赖线程。换句话说,就是进程中的最小执行单位就是线程,并且一个进程中至少有一个线程。
那什么又是多线程呢?
提到多线程这里要说两个概念,就是串行和并行,搞清楚这个,我们才能更好地理解多线程。

  • 串行,其实是相对于单条线程来执行多个任务来说的,我们就拿下载文件来举个例子:当我们下载多个文件时,在串行中它是按照一定的顺序去进行下载的,也就是说,必须等下载完A之后才能开始下载B,它们在时间上是不可能发生重叠的。

  • 并行:下载多个文件,开启多条线程,多个文件同时进行下载,这里是严格意义上的,在同一时刻发生的,并行在时间上是重叠的。

了解完这两个概念之后,我们再来说什么是多线程,举个例子,比如我们打开联想电脑管家,电脑管家本身是一个程序,也可以说就是一个进程,它里面包括很多功能,电脑加速、安全防护、空间清理等等功能,如果对于单线程来说,无论我们想要电脑加速,还是空间清理,那么必须得一件事一件事的做,做完其中一件事再做下一件事,有一个执行顺序。但如果是多线程的话,我们可以在清理垃圾的同时进行电脑加速,还可以病毒查杀等等其他操作,这个就是在严格意义上的同一时刻发生的,没有先后顺序。
二、线程的创建

Java 提供了三种创建线程的方法:

  • 通过继承 Thread 类本身。(重点)
  • 通过实现 Runnable 接口。(重点)
  • 通过 Callable 和 Future 创建线程。(了解)
1.继承Thread类



  • 自定义线程类继承Thread类
  • 重写run()方法,编写线程执行体
  • 创建线程对象,调用start()方法启动线程
  1. /**
  2. * @ClassName ThreadDemo
  3. * @Description TODO 线程创建的第一种方式:继承Thread类
  4. * @Author ZhangHao
  5. * @Date 2022/12/10 11:45
  6. * @Version: 1.0
  7. */
  8. public class ThreadDemo extends Thread{
  9.     @Override
  10.     public void run() {
  11.         //新线程入口点
  12.         for (int i = 0; i < 100; i++) {
  13.             System.out.println("我在玩手机:"+i);
  14.         }
  15.     }
  16.     //主线程
  17.     public static void main(String[] args) {
  18.         //创建线程对象
  19.         ThreadDemo demo = new ThreadDemo();
  20.         demo.start();//启动线程
  21.         for (int i = 0; i < 1000; i++) {
  22.             System.out.println("我在吃饭:"+i);
  23.         }
  24.         //主线程和多线程并行交替执行
  25.         //总结:线程开启不一定立即执行,由cpu调度执行
  26.     }
  27. }
复制代码
写一个小小的案例:使用多线程实现网图下载

  • 需要导入一个commons-io-2.11.0-bin.jar (百度搜索下载,版本不限制)
  1. /**
  2. * @ClassName ImageDownload
  3. * @Description TODO 网图下载
  4. * @Author ZhangHao
  5. * @Date 2022/12/10 12:55
  6. * @Version: 1.0
  7. */
  8. public class ImageDownload extends Thread{
  9.     private String url;//网图下载地址
  10.     private String name;//网图名称
  11.    
  12.     public ImageDownload(String url,String name){
  13.         this.url = url;
  14.         this.name = name;
  15.     }
  16.    
  17.     @Override
  18.     public void run() {
  19.         WebDownloader webDownloader = new WebDownloader();
  20.         webDownloader.downloader(url,name);
  21.         System.out.println("下载了文件名:"+name);
  22.     }
  23.    
  24.     public static void main(String[] args) {
  25.         ImageDownload d1 = new ImageDownload("https://cn.bing.com/images/search?view=detailV2&ccid=64mezA1F&id=0567ED050842B109CEFE6D7C2E235E6513915D00&thid=OIP.64mezA1F6eYavcDWrgjHQgHaEK&mediaurl=https%3a%2f%2fimages.hdqwalls.com%2fwallpapers%2fcute-kitten-4k-im.jpg&exph=2160&expw=3840&q=Cat+Wallpaper+4K&simid=608031326407324483&FORM=IRPRST&ck=5E947A96CD5B48E39B116D48F58466AB&selectedIndex=12&ajaxhist=0&ajaxserp=0", "cat1.jpg");
  26.         ImageDownload d2 = new ImageDownload("https://cn.bing.com/images/search?view=detailV2&ccid=qXtg4Nx0&id=A80C30163A6B55D16D61F27E632239424517705F&thid=OIP.qXtg4Nx0BUoeUP53fz_HKgHaFI&mediaurl=https%3a%2f%2fimages8.alphacoders.com%2f856%2f856433.jpg&exph=2658&expw=3840&q=Cat+Wallpaper+4K&simid=608046255722156270&FORM=IRPRST&ck=986D5F99CF8474477F4A1F2DB2850C9D&selectedIndex=25&ajaxhist=0&ajaxserp=0", "cat2.jpg");
  27.         ImageDownload d3 = new ImageDownload("https://cn.bing.com/images/search?view=detailV2&ccid=kvYsfUHA&id=6311D8D1DC87AA4B69783A97020038B03827134D&thid=OIP.kvYsfUHAAQlEVW3Z3_EEWwHaEK&mediaurl=https%3a%2f%2fwallpapershome.com%2fimages%2fpages%2fpic_h%2f19418.jpg&exph=1080&expw=1920&q=Cat+Wallpaper+4K&simid=608016886736366855&FORM=IRPRST&ck=37C2818B80D19766E7A91B5BB7A060D6&selectedIndex=159&ajaxhist=0&ajaxserp=0", "cat3.jpg");
  28.         d1.start();
  29.         d2.start();
  30.         d3.start();
  31.         //每次执行结果有可能不一样,再次证明线程之间是由cpu调度执行
  32.     }
  33. }
  34. //下载器
  35. class WebDownloader{
  36.     //下载方法
  37.     public void downloader(String url,String name){
  38.         try {
  39.             FileUtils.copyURLToFile(new URL(url),new File(name));
  40.         } catch (IOException e) {
  41.             e.printStackTrace();
  42.             System.out.println("IO异常,downloader方法出现问题!");
  43.         }
  44.     }
  45. }
复制代码
2. 实现Runnable接口



  • 定义MyRunnable类实现Runnable接口
  • 实现run()方法,编写线程执行体
  • 创建线程对象,调用start()方法启动线程
  1. /**
  2. * @ClassName RunnableDemo
  3. * @Description TODO 线程创建的第二种方式:实现Runnable接口 (推荐使用)
  4. * @Author ZhangHao
  5. * @Date 2022/12/10 15:07
  6. * @Version: 1.0
  7. */
  8. //模拟抢火车票
  9. public class RunnableDemo implements Runnable{
  10.     //票数
  11.     private int ticketNums = 10;
  12.     @Override
  13.     public void run() {
  14.         while (ticketNums > 0){
  15.             try {
  16.                 //让线程睡眠一会
  17.                 Thread.sleep(10);
  18.             } catch (InterruptedException e) {
  19.                 e.printStackTrace();
  20.             }
  21.             System.out.println(Thread.currentThread().getName()+"-->抢到了第"+ticketNums--+"张票");
  22.         }
  23.     }
  24.     public static void main(String[] args) {
  25.         //创建runnable接口的实现类对象
  26.         RunnableDemo demo = new RunnableDemo();
  27.         //创建线程对象,通过线程对象开启线程(使用的代理模式)
  28.         //Thread thread = new Thread(demo,"老王");
  29.         //thread.start();
  30.         //简写:new Thread(demo).start();
  31.         new Thread(demo,"老王").start();
  32.         new Thread(demo,"小张").start();
  33.         new Thread(demo,"黄牛党").start();
  34.         //发现问题:多个线程操作同一个资源时,线程不安全,数据紊乱。(线程并发)
  35.     }
  36. }
复制代码
再来一个小小的案例:模拟《龟兔赛跑》首先得有一个赛道,兔子天生跑得快,但是兔子跑一段路就偷懒睡觉,乌龟在不停的跑,最终乌龟取得胜利!
[code]/** * @ClassName Race * @Description TODO 模拟龟兔赛跑 * @Author ZhangHao * @Date 2022/12/11 9:25 * @Version: 1.0 */public class Race implements Runnable {    private static String winner;//胜利者    @Override    public void run() {        //设置赛道        for (int i = 1; i
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表