Java多线程01:线程的创建

进程和线程

  • 程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念

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

  • 线程是CPU调度和执行的单位,一个进程至少有一个线程

创建线程的三种方式

继承Thread类(不建议使用,避免单继承局限性)

步骤

  • 自定义线程类继承Thread类
  • 重写run()方法,编写线程执行体
  • 创建线程对象,调用start()方法启动线程
//创建线程方式一:继承Thread类,重写run()方法,调用start()方法开启线程
public class Hello extends Thread{
    //线程入口点
    @Override
    public void run() {
        //run()方法执行体
        for (int i = 0; i < 1000; i++) {
            System.out.println("这是子线程");
        }
    }

    //main()线程,主线程
    public static void main(String[] args) {
        //创建线程对象
        Hello thread = new Hello();
        //调用start()方法开启线程,main()线程也同时往下运行,不会等待;如果改为thread.run();,那就是单线程了
        //线程开启不一定立即执行,由CPU调度执行
        thread.start();

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

练习:多线程下载图片

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

//使用多线程同步下载图片
public class Hello extends Thread{
    //定义属性和构造方法
    String url;
    String name;
    public Hello(String url, String name) {
        this.url = url;
        this.name = name;
    }

    //重写run()方法
    @Override
    public void run() {
        //线程执行体,在这儿创建下载器对象,参数由创建线程对象时传入
        new Download().download(url, name);
        System.out.println("下载文件名为:" + name);
    }

    //main主线程
    public static void main(String[] args) {
        //创建多个线程对象
        Hello h1 = new Hello("https://img-blog.csdn.net/20160522165107051", "1.jpg");
        Hello h2 = new Hello("https://img-blog.csdn.net/20160522165107051", "2.jpg");
        Hello h3 = new Hello("https://img-blog.csdn.net/20160522165107051", "3.jpg");
        //启动线程,可以看到图片的下载顺序每次都不一样
        h1.start();
        h2.start();
        h3.start();
    }
}

//创建下载器类
class Download{
    public void download(String url, String name){
        try {
            //使用common-io.jar包的FileUtils工具类下载,此处传入的参数,看JDK文档是URL类型,也就是URL类的对象
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("下载出现异常");
        }
    }
}

实现Runnable接口(推荐使用)

推荐使用Runnable接口实现类,不仅避免单继承的局限性,还方便同一个对象被多个线程使用

//创建线程方式二:实现Runnable接口,重写run()方法,创建Thread对象调用start()方法开启线程
public class Hello implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("这是子线程");
        }
    }
    
    public static void main(String[] args) {
        Hello hello = new Hello();
        //没有直接继承Thread类,因此需要手动创建Threa对象调用start()方法
        new Thread(hello).start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("这是主线程");
        }
    }
}

练习:抢火车票

发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱

public class Hello implements Runnable {

    //火车票的数量
    int num = 10;

    @Override
    public void run() {
        //此处不能用for循环,那样在break时有的线程会出现抢到了票但来不及打印出来的情况
        while (true) {

            //模拟延时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (num <= 0) {
                break;
            }
            System.out.println(Thread.currentThread().getName() + "抢到了第" + num-- +"张票");
            //此处如果把num--;写在了下一行,会导致第10张票被抢3次
//                num--;
        }
    }

    public static void main(String[] args) {
        Hello hello = new Hello();
        new Thread(hello, "老师").start();
        new Thread(hello, "学生").start();
        new Thread(hello, "黄牛").start();
    }
}

练习:龟兔赛跑

public class Hello implements Runnable {
    boolean flag = false;

    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            //只要胜者出现了,就一直break,其他线程无法再继续跑
            if (flag) {
                break;
            }
            System.out.println(Thread.currentThread().getName() + "----->跑了" + i + "步");
            //设置获胜者的判断,当出现胜者时,其他线程不可再继续进行,避免出现多个胜者
            if (i == 100) {
                flag = true;
                System.out.println(Thread.currentThread().getName() + "赢了!");

            }
        }
    }

    public static void main (String[]args){
        Hello hello = new Hello();
        new Thread(hello, "兔子").start();
        new Thread(hello, "乌龟").start();
    }
}

实现Callable接口(了解即可)

Java多线程01:线程的创建

上一篇:《信息安全系统设计与实现》选做一


下一篇:Flutter 2.5 更新详解