Java多线程基础

时间:2024-02-16 10:54:47

Java多线程基础(1)

学习笔记为手打,教程为 【狂神说Java】多线程详解

线程基础

1. 线程就是独立执行路径

2. 在程序运行时,及时没有自己创建线程,后台夜会有多个线程,如主线程,gc线程

3. main()称之为主线程,为系统的入口,用于执行整个程序

4. 在一个进程中,如果开辟多个线程,线程的运作有调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的干预的

5. 对同一份资源操作时,会存在资源抢夺问题,需要加入并发控制

6. 线程会带来额外的开销,如cpu调度时间,并发控制开销

7. 每个线程在自己的工作内存交互,内存控制不当会造成数据的不一致

线程创建

三种创建方式

Thread class

子类继承Thread具备多线程功能

启动线程:子类对象.start()

OOP单继承局限性

public class ThreadsDemo2 extends Thread{



    private String url;  /*网络图片位置*/



    private String name;  /*文件名称*/


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


    }

    //下载图片的执行体
    @Override
    public void run() {

        WebDownloader webDownloader = new WebDownloader();
        try {
            webDownloader.downloader(url,name);
            System.out.println("下载图片为"+ name);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        String url1 = "https://img0.baidu.com/it/u=4156074303,275806129&fm=26&fmt=auto&gp=0.jpg";
        String url2 = "https://img1.baidu.com/it/u=1684000154,1654099979&fm=26&fmt=auto&gp=0.jpg";
        String url3 = "https://img0.baidu.com/it/u=1506294494,3075748085&fm=26&fmt=auto&gp=0.jpg";

        String name1 = "头像1.jpg";
        String name2 = "头像2.jpg";
        String name3 = "头像3.jpg";

        ThreadsDemo2 t1= new ThreadsDemo2(url1,name1);
        ThreadsDemo2 t2= new ThreadsDemo2(url1,name2);
        ThreadsDemo2 t3= new ThreadsDemo2(url1,name3);
        t1.start();
        t2.start();
        t3.start();
    }
}

/**
 * 下载器
 */
class WebDownloader {
    public void downloader(String url, String name) throws IOException {
        FileUtils.copyURLToFile(new URL(url), new File(name));
    }
}

第一次执行
image

第二次执行

imageimage

结论:两次执行的次序并不按顺序,可知三个线程是并行的。

Runnable interface

实现Runnable具有多线程能力

启动线程:传入目标对象+thread对象.start()

灵活,方便对象被多个线程使用

public class ThreadsDemo3  implements Runnable{

    @Override
    public void run() {
        //run()方法线程体
        for (int i = 0; i < 200; i++) {
            System.out.println("========run"+i);
        }
    }

    public static void main(String[] args) {

        ThreadsDemo3 t1 = new ThreadsDemo3();
        new Thread(t1).start();

        for (int i = 0; i < 2000; i++) {
            System.out.println("======main"+i);
        }
    }
}


Callable interface (暂时了解 21/08/23)

public class ThreadsDemo6 implements Callable<Boolean> {
    private String url;  /*网络图片位置*/

    private String name;  /*文件名称*/

    public ThreadsDemo6(String url1, String name1) {
        this.url = url1;
        this.name = name1;
    }


    @Override
    public Boolean call() throws Exception {
        WebDownloader webDownloader = new WebDownloader();
        try {
            webDownloader.downloader(url,name);
            System.out.println("下载图片为"+ name);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        String url1 = "https://img0.baidu.com/it/u=4156074303,275806129&fm=26&fmt=auto&gp=0.jpg";
        String url2 = "https://img1.baidu.com/it/u=1684000154,1654099979&fm=26&fmt=auto&gp=0.jpg";
        String url3 = "https://img0.baidu.com/it/u=1506294494,3075748085&fm=26&fmt=auto&gp=0.jpg";

        String name1 = "头像1.jpg";
        String name2 = "头像2.jpg";
        String name3 = "头像3.jpg";

        ThreadsDemo6 t1= new ThreadsDemo6(url1,name1);
        ThreadsDemo6 t2= new ThreadsDemo6(url1,name2);
        ThreadsDemo6 t3= new ThreadsDemo6(url1,name3);

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

        //提交执行
        Future<Boolean> r1 =executorService.submit(t1);
        Future<Boolean> r2 =executorService.submit(t2);
        Future<Boolean> r3 =executorService.submit(t3);

        //获取结果

        Boolean rs1 = r1.get();
        Boolean rs2 = r2.get();
        Boolean rs3 = r3.get();

        //关闭服务
        executorService.shutdownNow();
    }
}

线程并发

发现问题

多个线程操作同一个资源识,线程不安全,数据紊乱

public class ThreadsDemo4 implements Runnable{
    private int ticketNum = 10;
    @Override
    public void run() {

        while (true){
            if (ticketNum <1 ) {
                break;
            }
            System.out.println( Thread.currentThread().getName()+ "===>拿了第"+ticketNum-- +"票");
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        ThreadsDemo4 ticket = new ThreadsDemo4();
        new Thread(ticket, "XiaoMing").start();
        new Thread(ticket, "XiaoHong").start();
        new Thread(ticket, "HuangNiu").start();
    }
}

image

加深对多线程的印象——模拟龟兔赛跑

public class ThreadsDemo5 implements Runnable {
    //胜利者
   private static String winner;
   //跑道长度
    private static int RUNWAY_LENGTH  = 50;
    //游戏结束标志
    boolean gameOver(int i){
        //胜者唯一
        if (winner!=null){
            return true;
        }

        if( i >= RUNWAY_LENGTH){
            winner = Thread.currentThread().getName();
            System.out.println("===比赛结束==="+"\n"+winner+"-->获得了胜利");

            return true;
        }
        return false;
    }
    @Override
    public void run() {


        for (int i = 0; i <= RUNWAY_LENGTH; i++) {

            boolean flag = gameOver(i);
            if (flag) {
                break;
            }
            String name = Thread.currentThread().getName();

            System.out.println(name + "-->已经跑了" + i + "米");

            //兔子跑的快
            if ("兔子".equals(name)){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //乌龟爬的慢
            if ("乌龟".equals(name)) {
                System.out.println("加油!!!!");
                try {
                    Thread.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //兔子半路睡着
             if ("兔子".equals(name) && i == RUNWAY_LENGTH/2){
                System.out.println("怎么能睡觉呢?\n");
                try {
                    Thread.sleep(60);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }


        }

    }

    public static void main(String[] args) {

        ThreadsDemo5 race = new ThreadsDemo5();
        new Thread(race,"兔子").start();
        new Thread(race,"乌龟").start();
    }

}

image