【Java进阶】多线程详解

【Java进阶】多线程详解,第1张

前言

本系列记录Java从入门开始的知识点,多线程详解:线程简介,线程实现,线程状态,线程同步,线程通信问题,高级主题。

文章目录
  • 前言
  • 一、线程简介
    • 1、Process与Thread
    • 2、核心概念
  • 二、线程实现
    • 1、三种线程创建方式
    • 2、继承Thread类
    • 2、实现Runnable接口
    • 3、小结Thread类和Runnable接口
    • 4、火车票例子(并发问题)


一、线程简介 1、Process与Thread
  1. 程序:程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
  2. 进程:执行程序的一次执行过程,是一个动态的概念,进程是系统资源分配的单位
  3. 线程:通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程。线程是CPU调度和执行的单位
2、核心概念
  1. 线程是独立的执行路径;
  2. 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
  3. main()称之为主线程,为系统的入口,用于执行整个程序;
  4. 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与 *** 作系统紧密相关的,先后顺序时不能人为干预的;
  5. 对同一份资源 *** 作时,会存在资源抢夺的问题,需要加入并发控制;
  6. 线程会带来额外的开销,如CPU调度时间,并发控制开销;
  7. 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。
二、线程实现 1、三种线程创建方式

2、继承Thread类

将一个类声明为Thread的子类。 这个子类应该重写run类的方法Thread 。 然后可以分配并启动子类的实例.

  1. start()是同时执行,run()不是。
//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程
public class TestThread1 extends Thread{
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("看run==="+i);
        }
    }

    public static void main(String[] args) {
        //main线程,主线程
        TestThread1 testThread1 = new TestThread1();
        testThread1.start();

        for (int i = 0; i < 2000; i++) {
            System.out.println("看主线程==="+i);
        }
    }
}

左:start,右:run。

  1. 练习Thread,实现多线程同步下载图片
    (1)下载commons-io.jar包;
    (2)创建lib包,把commons-io.jar包放入lib中,并导入;

    (3)编写代码
package Thread.demo01;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;

//练习Thread,实现多线程同步下载图片
public class TestThread2 extends Thread{

    private String url;
    private String name;

    public TestThread2(String url, String name) {
        this.url = url;
        this.name = name;
    }

    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名"+name);
    }

    public static void main(String[] args) {
        TestThread2 t1 = new TestThread2("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-8431442783f60d9efc2ffda7e04e8691_r.jpg&refer=http%3A%2F%2Fpic4.zhimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1654483941&t=6a2e2aa2fae724a90400672ab949aef8","cat1.jpg");
        TestThread2 t2 = new TestThread2("http://www.kaotop.com/file/tupian/20220508/spanspan cat2.jpg");
        TestThread2 t3 = new TestThread2("http://www.kaotop.com/file/tupian/20220508/spanspan cat3.jpg");

        t1.start();
        t2.start();
        t3.start();
    }
}

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

2、实现Runnable接口

创建一个线程是声明实现类Runnable接口。 那个类然后实现了run方法。 然后可以分配类的实例,在创建Thread时作为参数传递,并启动。其实和Thread很像,只是要将Thread最为参数传递进去。

//创建线程方式2:实现runnable接口,重写run方法,执行线程需要丢入runnable接口的实现类,调用start方法。
public class TestThread3 implements Runnable{
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("看run==="+i);
        }
    }

    public static void main(String[] args) {
        //创建runnable接口的实现类对象
        TestThread3 testThread3 = new TestThread3();

        //创建线程对象,通过线程对象来开启我们的线程,代理
//        Thread thread = new Thread(testThread3);
//        thread.start();
        new Thread(testThread3).start();

        for (int i = 0; i < 2000; i++) {
            System.out.println("看主线程==="+i);
        }
    }
}
3、小结Thread类和Runnable接口

4、火车票例子(并发问题)
public class TestThread5 implements Runnable{

    private int tickeNums = 10;

    @Override
    public void run() {
        while(true){
            if(tickeNums<=0){break;}
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"-->拿到了第"+tickeNums--+"张票");
        }
    }

    public static void main(String[] args) {
        TestThread5 ticket = new TestThread5();
        new Thread(ticket,"法外狂徒张三").start();
        new Thread(ticket,"不明真相李四").start();
        new Thread(ticket,"实在冤枉王五").start();
    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/874177.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存