多线程(一):认识线程,创建线程和线程的常用方法

Posted 头发都哪去了

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程(一):认识线程,创建线程和线程的常用方法相关的知识,希望对你有一定的参考价值。

概念

进程是系统分配资源的最小单位,线程是系统调度的最小单位。一个进程内的线程之间是可以共享资源的。每个进程至少有一个线程存在,即主线程。
在这里插入图片描述

例程:实现字符缓慢输出

public class ThreadDemo1 {
    public static void main(String[] args) throws InterruptedException {
        String content = "别人说你不行,是因为他自己做不到。你要尽全力保护你的梦想,那些嘲笑你的人,他们必定会失败," +
                "他们想把你变成和他们一样的人。如果你有梦想的话,就要努力去实现, 就这样。";
        for (char item : content.toCharArray()) {
            System.out.print(item);
            //执行到此行休眠200毫秒
            Thread.sleep(200);
        }
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

多线程的优势-增加运行速度

可以观察下面这个多线程例程,体验多线程时如何怎加运行速度的。

public class ThreadDemo2 {

    //执行的循环次数
    private static final Long count = 5_0000_0000L;

    public static void main(String[] args) throws InterruptedException {

//        System.out.println(Thread.currentThread().getName());

        //调用多线程的方法
        concorrency();

        //调用单线程的方法
        serial();
    }

    //单线程的方法
    private static void serial() {
        //记录开始时间
        Long stime = System.currentTimeMillis();//记录当前时间的毫秒时间戳
//        System.nanoTime();//当前时间的纳秒时间戳(更精确)
        int a = 0;
        //执行15亿次循环
        for (int i = 0; i < 3 * count; i++) {
            a++;
        }
        //记录结束时间
        Long etime = System.currentTimeMillis();
        System.out.println("单线程执行了: " + (etime - stime));
    }

    //多线程的方法
    private static void concorrency() throws InterruptedException {
        //开始时间
        Long stime = System.currentTimeMillis();

        //执行15亿次循环
        //创建了线程任务
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                //具体业务
                int a = 0;
                for (int i = 0; i < count; i++) {
                    a++;
                }
            }
        });
        //开始执行线程
        t1.start();

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                int b = 0;
                for (int i = 0; i < count; i++) {
                    b++;
                }
            }
        });
        t2.start();

        //让主线程执行5亿次
        int c = 0;
        for (int i = 0; i < count; i++) {
            c++;
        }

        //等待线程t1和t2执行完成之后,再统计时间
        t1.join();
        t2.join();

        //结束时间
        Long etime = System.currentTimeMillis();
        System.out.println("多线程执行了: " + (etime - stime));
    }
}

该代码运行结果如下:
在这里插入图片描述
可见,多线程的优势,可以增加运行速度,缩短运行时间的。

线程的创建方式,动手接触线程(三类六种)

第一类:继承Thread类来实现线程的创建(2种创建方式)

创建方式①

/*
 * 第一类:继承 Thread 类创建方法1
 */
public class ThreadDemo3 {
    static class MyThread extends Thread {
        @Override
        public void run() {
            //线程执行的任务
            System.out.println("线程名称: " +
                    Thread.currentThread().getName());
        }
    }

    public static void main(String[] args) {
        System.out.println("当前线程的名称(主线程):" +
                Thread.currentThread().getName());
        //创建了线程
        Thread t1 = new MyThread();
        //运行线程
        t1.start();
    }
}

该代码执行如下
在这里插入图片描述

创建方式②

/*
 * 第一类:继承 Thread 类创建方法2
 */
public class ThreadDemo4 {
    public static void main(String[] args) {
        System.out.println("当前线程的名称(主线程):" +
                Thread.currentThread().getName());
        Thread thread = new Thread() {
            @Override
            public void run() {
                //线程执行的任务
                System.out.println("线程名称: " +
                        Thread.currentThread().getName());
            }
        };
        thread.start();
    }
}

该代码执行如下
在这里插入图片描述

第一类创建方式(继承Thread类的方式)缺点:
Java 语言的设计当中,只能实现单继承,如果该类继承了Thread类,也就无法继承其他类。

第二类:实现Runnable接口的方式来实现线程的创建(3种创建方式)

弥补了第一类创建方法的缺点,即Java不能多继承,但可以实现多个接口

创建方式①

public class ThreadDemo5 {
    static class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("线程名: " +
                    Thread.currentThread().getName());
        }
    }

    public static void main(String[] args) {
        System.out.println("当前线程的名称(主线程):" +
                Thread.currentThread().getName());

        //1.新建 Runnable 类
        MyRunnable runnable = new MyRunnable();
        //2.新建 Thread
        Thread thread = new Thread(runnable);
        //3.启动线程
        thread.start();
    }
}

该代码执行如下
在这里插入图片描述
创建方式②:使用匿名内部类的方式实现线程

public class ThreadDemo6 {
    public static void main(String[] args) {
        System.out.println("当前线程的名称(主线程):" +
                Thread.currentThread().getName());

        //使用匿名内部类的方式实现线程
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程名: " +
                        Thread.currentThread().getName());
            }
        });
        thread.start();
    }
}

该代码执行如下
在这里插入图片描述
创建方式③:lambda + 匿名 Runnable 的实现方式

public class ThreadDemo7 {
    public static void main(String[] args) {
        System.out.println("当前线程的名称(主线程):" +
                Thread.currentThread().getName());

        //JDK8中的固定写法
        //lambda + 匿名 Runnable 的实现方式
        Thread thread = new Thread(() -> {
            System.out.println("线程名: " +
                    Thread.currentThread().getName());
        });
        thread.start();
    }
}

该代码执行如下
在这里插入图片描述

第三类:实现Callable接口的方式来实现线程的创建(1种创建方式)

优点在于可以得到线程执行之后的结果。

public class ThreadDemo8 {
    //创建了线程的任务和返回方法
    static class MyCallable implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            // 生成一个随机数
            int num = new Random().nextInt(10) + 1;
            System.out.println("子线程:" +
                    Thread.currentThread().getName() +
                    ",随机数:" + num);
            return num;
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 1.创建一个 Callable
        MyCallable myCallable = new MyCallable();
        // 2.创建一个 FutureTask 对象来接收返回值
        FutureTask<Integer> futureTask =
                new FutureTask<>(myCallable);
        // 3.创建 Thread
        Thread thread = new Thread(futureTask);
        // 启动线程
        thread.start();
        // 得到线程执行结果
        int result = futureTask.get();
        System.out.println(String.format("线程名:%s,数字:%d",
                Thread.currentThread().getName(), result));
    }
}

该代码执行结果如下
在这里插入图片描述

线程休眠(实现方式有三种)

实现方法①
优点:精确度很高。
缺点:当休眠时间过大时,代码书写较复杂。

public class ThreadDemo9 {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("开始时间: " + new Date());
        //休眠1s
        Thread.sleep(1000);
        System.out.println("结束时间: " + new Date());
    }
}

代码执行结果如下
在这里插入图片描述

当休眠较长时间,可用实现方法②和实现方法③。
实现方法②

public class ThreadDemo9 {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("开始时间: " + new Date());
        //休眠1s
        TimeUnit.SECONDS.sleep(1);
        System.out.println("结束时间: " + new Date());
    }
}

该代码执行结果如下
在这里插入图片描述
实现方法③

public class ThreadDemo9 {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("开始时间: " + new Date());
        //休眠1s
        Thread.sleep(TimeUnit.SECONDS.toMillis(1));
        System.out.println("结束时间: " + new Date());
    }

该代码执行结果如下
在这里插入图片描述

典型例题:使用两个线程来打印"AABBCCDD"。

解题思路:使用多线程+线程休眠即可完成题目要求

public class ThreadDemo10 {
    public static void main(String[] args) {
        //创建一个任务
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                String data = "ABCD";
                for (char item : data.toCharArray()) {
                    System.out.print(item);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        Thread t1 = new Thread(runnable);
        Thread t2 = new Thread(runnable);
        t1.start();
        t2.start();
    }
}

该代码执行结果如下
在这里插入图片描述

以上是关于多线程(一):认识线程,创建线程和线程的常用方法的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程的概念特性线程的创建方式以及线程的常用方法

详细讲解 —— 多线程初阶认识线程(Java EE初阶)

四万字长文总结多线程,一篇就够了!

四万字长文总结多线程,一篇就够了!

四万字长文总结多线程,一篇就够了!

多线程---再次认识volatile,Synchronize,lock