01线程实现

Thread class 继承Thread(重点)

创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例。

继承类必须重写 run() 方法,该方法是新线程的入口点。

它也必须调用 start() 方法才能执行。

该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例。

//创建线程方法一:继承Thread类,重写Run()方法,调用start()开启线程
public class TestThread01 extends Thread{
    @Override
    public void run() {
        //run方法线程体
        for (int i=0;i<200;i++){
            System.out.println("线程" + i);
        }
    }
    public static void main(String[] args) {
        //main线程,主线程
        //创建一个线程对象
        TestThread01 testThread01 = new TestThread01();
        //调用start()方法开启线程
        testThread01.start();
        for (int i=0;i<2000;i++){
            System.out.println("线程ar" + i);
        }
    }
}

线程会穿插在主线程中出现

总结:线程开启不一定立即执行,由CPU调度执行

在这里插入图片描述

线程在主线程ar中穿插执行,且每次位置也可能不同,由CPU决定

多线程下载(IDM)

import org.apache.commons.io.FileUtils;

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

public class TestThread02 extends Thread {
    private String url;//网络图片地址
    private String name;//保存的文件名

    public TestThread02(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) {
        TestThread02 testThread02 = new TestThread02("https://img-blog.csdnimg.cn/20190318201755609.png","2.png");
        TestThread02 testThread03 = new TestThread02("https://img-blog.csdnimg.cn/20190318201755609.png","3.png");
        TestThread02 testThread04 = new TestThread02("https://img-blog.csdnimg.cn/20190318201755609.png","4.png");
        testThread02.start();
        testThread03.start();
        testThread04.start();
    }
}
//下载器
class WebDownLoader{
    //下载方法
    public void downloader(String url,String name) {
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            System.out.println("io异常,downloader方法出现异常");
        }
    }
}


(同时执行,不一定按顺序,是根据下好的时间来排的)

Runnable接口 实现Runnable接口(重点)

//改的第一个
public class TestThread03 implements Runnable{
    @Override
    public void run() {
        //run方法线程体
        for (int i=0;i<200;i++){
            System.out.println("线程" + i);
        }
    }
    public static void main(String[] args) {
        //创建一个Runnable接口的实现类对象
        TestThread03 testThread03 = new TestThread03();
//        //创建线程对象,通过线程对象打开线程,代理
//        Thread thread = new Thread(testThread03);
//        thread.start();
        new Thread(testThread03).start();
        for (int i=0;i<1000;i++){
            System.out.println("线程ar" + i);
        }
    }
}

在这里插入图片描述

//改的第二个

public class TestThread02 implements Runnable {
    private String url;//网络图片地址
    private String name;//保存的文件名

    public TestThread02(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) {
        TestThread02 testThread02 = new TestThread02("https://img-blog.csdnimg.cn/20190318201755609.png","2.png");
        TestThread02 testThread03 = new TestThread02("https://img-blog.csdnimg.cn/20190318201755609.png","3.png");
        TestThread02 testThread04 = new TestThread02("https://img-blog.csdnimg.cn/20190318201755609.png","4.png");
        new Thread(testThread02).start();
        new Thread(testThread03).start();
        new Thread(testThread04).start();
    }
}
//下载器
class WebDownLoader{
    //下载方法
    public void downloader(String url,String name) {
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            System.out.println("io异常,downloader方法出现异常");
        }
    }
}
对比:继承Thread VS Runnable()

继承Thread类

  • 子类继承Thread类具备多线程能力
  • 启动线程:子类对象. start()
  • 不建议使用:避免OOP单继承局限性

实现Runnable接口

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

并发

//数据不安全,会出现紊乱,
public class TestThread04 implements Runnable {
    //票数
    private int ticksNums=10;
    @Override
    public void run() {
        while (true){
            if (ticksNums<=0){
                break;
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"抢到了" + ticksNums-- + "票");
        }
    }

    public static void main(String[] args) {
        TestThread04 ticket = new TestThread04();
        new Thread(ticket,"ar").start();
        new Thread(ticket,"kimi").start();
        new Thread(ticket,"alice").start();
    }
}

ar抢到了9票
kimi抢到了8票
alice抢到了10票
ar抢到了7票
alice抢到了6票
kimi抢到了7票
alice抢到了5票
kimi抢到了4票
ar抢到了3票
alice抢到了2票
ar抢到了2票
kimi抢到了2票
alice抢到了1票
ar抢到了-1票
kimi抢到了0票

龟兔赛跑

import java.lang.Thread;
import java.lang.Runnable;
class Rabbit implements Runnable{
    private String name;
    static int rabbit_walk=0;         //兔子跑过的距离
    public Rabbit(String name) {
        this.name=name;
    }
    public String getName(){
        return this.name;
    }
    public synchronized void run() {
        System.out.println("兔子开始跑了...");
        for(int i=0;i<=500;i+=5) {
            System.out.println(this.getName()+"跑了"+i+"米");
            if(i%20==0) {
                try {
                    Thread.sleep(50);
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }
            rabbit_walk+=5;
            if(Tortoise.tortoise_walk==500)
                break;
            if(i==500) {
                System.out.println(this.getName()+"跑完了全程");
                System.out.println("胜利者是"+this.getName());
            }
        }
        return;
    }
}
class Tortoise implements Runnable{
    private String name;
    static int tortoise_walk=0;            //乌龟跑过的距离
    public Tortoise(String name) {
        this.name=name;
    }
    public String getName() {
        return this.name;
    }
    public synchronized void run() throws NullPointerException{
        System.out.println("乌龟开始跑了...");
        for(int i=0;i<=500;i++) {
            System.out.println(this.getName()+"跑了"+i+"米");
            if(i%500==0) {
                try {
                    Thread.sleep(500);
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Tortoise.tortoise_walk+=1;
            if(Rabbit.rabbit_walk==500)
                break;
            if(i==500) {
                System.out.println(this.getName()+"跑完了全程");
                System.out.println("胜利者是"+this.getName());
            }
        }
        return;
    }
}
class Runtest {
    public static void main(String[] args) {
        Thread t1 = new Thread(new Rabbit("兔子"));
        Thread t2 = new Thread(new Tortoise("乌龟"));
        t1.start();
        t2.start();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SyFzxNT6-1639908403095)(C:\Users\17730\AppData\Roaming\Typora\typora-user-images\image-20211219175902111.png)]

Callable接口 实现Callable接口(了解)

当实现Callable接口之后,要重写接口中的call方法,call方法中的代码作为线程执行体,此时的call方法可以有返回值。

​ Callable接口是Java5中新增的接口,不是Runnable接口的子接口,所以Callable对象不能直接作为Thread对象的Target,于是Java5中提供了Future接口来代表Callable接口里call方法的返回值,并为Future接口提供了一个FutureTask实现类,它实现了Future接口和Runnable接口,可以作为Thread类的Target。所以在创建Callable

接口实现类之后,要用FutureTask来包装Callable对象(实现手动装箱)。然后用FutureTask对象作为Target。

Callable接口是Java5中新增的接口,不是Runnable接口的子接口,所以Callable对象不能直接作为Thread对象的Target,于是Java5中提供了Future接口来代表Callable接口里call方法的返回值,并为Future接口提供了一个FutureTask实现类,它实现了Future接口和Runnable接口,可以作为Thread类的Target。所以在创建Callable

接口实现类之后,要用FutureTask来包装Callable对象(实现手动装箱)。然后用FutureTask对象作为Target。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值