栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

多线程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

多线程

1.线程简介

java.thread
任务:
同一时间只能做一件事

由上图可知:
调用 run();方法并不会开启新线程;
调用 start();方法会开启新线程。

程序:是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
进程(process):实质性程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位;

进程和线程的关系:通常再一个进程中可以包含若干个线程,一个进程至少有一个线程,不然没有存在的意义。

线程(thread):是CPU调度和执行的单位

注意:很多 多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为其切换的很快,所以就有同时执行的错觉。

核心概念:
- 县城就是独立的执行路径;
- 在程序执行时,即使没有自己创建线程,后台也会有多个线程,比如:主线程,GC线程;
- main() 称之为主线程,是系统的入口,用于执行整个程序;
- 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密想关的,先后顺序是不能人为干预的;
- 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
- 线程会带来额外的开销,比如cpu调度时间,并发控制开销。
- 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。
2.线程的创建(重点)

实现现成的三种方式:

继承 Thread类(重点),底层继承 runnable
实现 Runnable接口(*重点)
实现 Callable接口(现阶段—了解)

2.1. 继承Thread类,创建线程(重点)

public class Thread
Thread extends Object
implements Runnable

线程是程序中执行的线程。 Java虚拟机允许应用程序同时执行多个执行线程。
每个线程都有优先权。 具有较高优先级的线程优先于优先级较低的线程执行。

创建一个新的执行线程有两种方法。
方法1:是将一个类声明为Thread的子类。 这个子类应该重写run类的方法Thread 。 然后可以分配并启动子类的实例。 例如,计算大于规定值的素数的线程可以写成如下:

public class TestThread_1 extends Thread{
   //重写 run();方法,方法线程体
   @Override
   public void run() {
       for (int i = 0; i < 20; i++) {
           System.out.println("看代码---"+ i);
       }
   }

   //main方法,主线程
   public static void main(String[] args) {
       //创建一个线程对象
       TestThread_1 testThread1 = new TestThread_1();
       //调用start()方法开启线程
       testThread1.start();

       for (int i = 0; i < 200; i++) {
           System.out.println("-------学习多线程----"+ i);
       }
   }
}

!!注意:线程不一定立即执行,CPU安排调度,(每次执行会有区别)

2.2. 实现Runnable接口,创建线程(重点)

方法2:是创建一个线程是声明实现类Runnable接口。 那个类然后实现了run方法。 然后可以分配类的实例,在创建Thread时作为参数传递,并启动。 这种其他风格的同一个例子如下所示:

public class TestThread_3 implements Runnable{
    //重写 run();方法, 方法线程体
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("看代码---"+ i);
        }
    }

    //main方法,主线程
    public static void main(String[] args) {
        //创建 runnable接口的实现类
        TestThread_3 testThread_3 = new TestThread_3();
        //创建线程对象,通过线程对象来开启我们的线程,(这是个代理)
        
        new Thread(testThread_3).start();

        for (int i = 0; i < 200; i++) {
            System.out.println("-------学习多线程----"+ i);
        }
    }
}

每个线程都有一个用于识别目的的名称。 多个线程可能具有相同的名称。 如果在创建线程时未指定名称,则会为其生成一个新名称。

除非另有说明,否则将null参数传递给null中的构造函数或方法将导致抛出NullPointerException 。

继承 Thread类:
	- 子类继承 thread类, 子类具备多线程能力
	- 启动线程:子类对象.start();
	- 不建议使用:避免OOP单继承局限性
实现 Runnable接口:
	- 实现 Runnable接口,具有多线程能力
	- 启动线程:传入目标对象+ Thread对象.start();
	- 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用

//一份资源
StartThread4 startThread = new StartThread4();

//多个代理
new Thread(station,"jack").start();
new Thread(station,"tom").start();
new Thread(station,"jerry").start();

案例3:

public class TestThread5 implements Runnable{
    // 票数
    private int ticketNums = 10;

    @Override
    public void run() {
        while (true) {
            if (ticketNums <= 0) {
                break;
            }

            // 模拟延时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //Thread.currentThread().getName()获取线程名称
            System.out.println(Thread.currentThread().getName() +"-->拿到了第"+ ticketNums--);
        }
    }

    public static void main(String[] args) {
        TestThread5 testThread5 = new TestThread5();

        new Thread(testThread5,"小明").start();
        new Thread(testThread5,"小红").start();
        new Thread(testThread5,"黄牛").start();
    }
}
2.3. 实现Callable接口,创建线程(了解)

步骤:

  1. 实现Callable接口,需要返回值类型
  2. 重写 call方法,需要抛出异常
  3. 创建目标对象
  4. 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
  5. 提交执行:Future< Boolean > result1 = ser.submit(t1);
  6. 获取结果:boolean r1 = result1.get();
  7. 关闭服务:ser.shutdownNow();
public class TestThread_7Callable implements Callable {
    //网络图片地址
    private String url;
    //保存的文件名字
    private String fileName;

    public TestThread_7Callable(String url, String fileName) {
        this.url = url;
        this.fileName = fileName;
    }

    //重写 call();方法,图片下载执行体
    @Override
    public Boolean call() throws Exception {
        WebDownloader3 webDownloader = new WebDownloader3();
        webDownloader.downloader(url, fileName);
        System.out.println("下载的文件名:" + fileName);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestThread_7Callable t1 = new TestThread_7Callable("https://t7.baidu.com/it/u=1595072465,3644073269&fm=193&f=GIF", "7.jpg");
        TestThread_7Callable t2 = new TestThread_7Callable("https://t7.baidu.com/it/u=1595072465,3644073269&fm=193&f=GIF", "8.jpg");
        TestThread_7Callable t3 = new TestThread_7Callable("https://t7.baidu.com/it/u=1595072465,3644073269&fm=193&f=GIF", "9.jpg");

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

        // 5.提交执行
        Future result1 = ser.submit(t1);
        Future result2 = ser.submit(t2);
        Future result3 = ser.submit(t3);

        // 6.获取结果,(call方法返回的结果)
        boolean r1 = result1.get();
        boolean r2 = result2.get();
        boolean r3 = result3.get();

        // 7.关闭服务
        ser.shutdownNow();
    }
}


class WebDownloader3 {
    //下载方法
    public void downloader(String url, String fileName) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(fileName));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,download方法出现问题");
        }
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/879973.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号