Loading

java线程的创建

Java多线程

image

方式一:继承Thread类

创建线程方式一:继承Thread类,重写run()方法,调用start开启线程。

run()方法中写要做的事情。

public class TestThread1 extends Thread{
    @Override
    //线程入口点
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码---"+i);
        }
    }

    public static void main(String[] args) {
        //创建线程对象
        TestThread1 testThread1 = new TestThread1();
        testThread1.start();
               
        for (int i = 0; i < 200; i++) {
            System.out.println("我在学习多线程---"+i);
        }
    }
}

如果直接调用run()方法,那么就只有一个主线程在执行。

这里调用start()方法,相当于同时开启两个线程(一个主线程+一个线程)

image

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


  • 案例:Thread实现网图下载
    • maven引入依赖commons-io
    • URL下载工具类FileUtils.copyURLToFile
package com.cc;

import org.apache.commons.io.FileUtils;

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

public class TestThread2 extends Thread {
    public String url;
    public 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);
    }

    public static void main(String[] args) {
        TestThread2 t1 = new TestThread2("https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2022/10/10/kuangstudyfabac30a-9e31-4ea0-bca8-739ca0f01892.png", "1.jpg");
        TestThread2 t2 = new TestThread2("https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2022/10/10/kuangstudybcc252b8-d410-4397-bf94-d5849e143b73.png", "2.jpg");
        TestThread2 t3 = new TestThread2("https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2022/10/10/kuangstudy3225d0ff-4ae7-457a-8c18-1662c35cc0db.png", "3.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));
            System.out.println(name+"下载成功");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("下载方法异常");
        }
    }

}

pom.xml

   <dependencies>
       <dependency>
           <groupId>commons-io</groupId>
           <artifactId>commons-io</artifactId>
           <version>2.6</version>
       </dependency>
   </dependencies>

方式二:实现runnable接口

实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法。

public class TestThread1 extends Thread{
    @Override
    //线程入口点
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码---"+i);
        }
    }

    public static void main(String[] args) {
        //创建runnable实现类
        TestThread1 testThread1 = new TestThread1();
        //创建线程对象,通过线程对象开启线程,这里是静态代理
        new Thread(testThread1).start();
        
        //对比继承Thread类

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

image

OOP:面向对象编程,单继承:一个子类只能继承一个父类。

方式一与方式二对比只有两点区别:

  1. 继承Thread类——>实现Runnable接口
  2. 子类对象.start()——> new Thread(实现类对象).start

初识并发问题

  • 案例:多个线程同时操作同一个对象
package com.cc;

public class TestThread4 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();
            }

            System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ ticketNums-- +"票");
        }
    }

    public static void main(String[] args) {
        TestThread4 ticket = new TestThread4();

        new Thread(ticket,"小明").start();
        new Thread(ticket,"小红").start();
        new Thread(ticket,"黄牛").start();
    }
}

image

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

  • 案例:龟兔赛跑
public class Race implements Runnable{


    private static String winner;
    @Override
    public void run() {
        for (int i = 0; i < 101; i++) {
            //判断是否完成比赛
            boolean flag = gameOver(i);
            if(flag) break;

            //模拟兔子睡觉
            if(Thread.currentThread().getName().equals("兔子")){
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            System.out.println(Thread.currentThread().getName() + "跑到了第" + i +"步");
        }
    }

    //判断是否完成比赛
    public boolean gameOver(int steps){
        if (winner!=null){
            return true;
        }{
            if(steps>=100){
                winner = Thread.currentThread().getName();
                System.out.println("winner is " + winner);
                return true;
            }
        }
        return false;
    }

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

方式三:实现callable接口

image

posted @ 2023-01-26 20:12  _rainyday  阅读(48)  评论(0)    收藏  举报