美文网首页Java
【多线程】——2.线程的创建

【多线程】——2.线程的创建

作者: 衰煋 | 来源:发表于2020-03-29 01:28 被阅读0次

    线程的创建

    Thread类:

    继承Thread类的方式创建线程

    重写run方法,在run方法内想做需要在子线程中完成的事情

    实例化Thread子类对象,就是创建了线程对象

    调用start方法就是开启了线程

    public class helloworld extends Thread {

        public static void main(String[] args) {

            System.out.println("====创建线程====");

            helloworld helloworld = new helloworld();

            System.out.println("====启动线程====");

            helloworld.start();

        }

        public void run(){

            System.out.println("hello:"+currentThread().getName());

        }

    }


    Runnable接口

    有一个类实现Runnable接口,重写run方法,整个run方法就是线程的执行体。

    创建Runnable的类,传到Thread类的构造函数里面去创建一个Thread类的对象,这个Thread对象才是真正的线程对象

    public class helloworld implements Runnable {

        public static void main(String[] args) {

            System.out.println("====实现runnable接口====");

            helloworld helloworld = new helloworld();

            System.out.println("====创建线程====");

            Thread thread = new Thread(helloworld);

            System.out.println("====启动线程====");

            thread.start();

        }

        public void run(){

            System.out.println("hello");

        }

    }

    Callable接口

    可以有返回值携带回来

    创建一个Callable的实现类,实现call方法,call方法里面装的就是线程的执行逻辑,且该call方法有返回值

    拿到Callable的实现类之后,FutureTask类来包装这个实现类。

    这个FutureTask对象封装了这个Callable实现类的call方法的返回值

    然后使用FutureTask对象作为参数,传到Thread类的构造函数里去,创建,启动一个线程,调用start方法让他去跑,跑完了以后可以用FutureTask的get方法获得子线程结束后的返回值

    public class helloworld  {

        public static void main(String[] args) {

            //FutureTask对象

            //Lambda表达式

            FutureTask task = new FutureTask(()->{

                int count = 0;

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

                    count += i;

                }

                return count;

            });

            //创建线程

            Thread thread = new Thread(task);

            //启动线程

            thread.start();

            try {

                //获取线程返回值

                System.out.println("1+2+3+...+100 ="+task.get());

            } catch (InterruptedException e) {

                e.printStackTrace();

            } catch (ExecutionException e) {

                e.printStackTrace();

            }

        }

        public void run(){

            System.out.println("hello");

        }

    }

    Callable接口使用场景

    比如查询商品列表

    对方没有批量接口,就用这个方法多线程分别查询每个商品信息,每个线程需要返回商品的信息,再组装,就是一口气并发出去接收回来,而不是一次次请求出去

    线程池创建线程

    /

    线程的生命周期

    新建 :new关键字创建线程对象的状态。

    就绪:通过线程对象的start方法启动线程时对应的状态,此时线程不一定马上进入运行状态,线程的运行由操作系统的调度程序控制当前CPU有空闲就很有可能直接执行,如果CPU没有空闲,这个线程没有能得到CPU的时间片,就不能立即执行。

    运行:得到了CPU的执行权,线程正在执行需要执行的代码。

    阻塞:线程被挂起,通常原因是在等待一个锁,没办法执行线程体。

    等待:分为有限期等待和无限期等待。无限期等待需要被唤醒。

    结束:线程结束,把相关资源释放掉。

    线程阻塞:

    1.线程在等待一个锁对象,比如代码里面加了一个synchronized方法块,锁被其他线程占有了,当前线程获取不到,就进行到了阻塞状态。或者发生了wait操作就进入等待状态了。

    2.对阻塞的线程调用thread.interrupt(),也无法改变其阻塞状态,因为thread.interrupt()只是设置线程中断状态,不能唤醒处于阻塞状态的线程。

    3.ReentrankLock.lock()操作后进入的是waiting状态,其内部调用的是LockSupport.park()方法

    线程无限期等待

    处于这种状态的线程不会被CPU分配执行时间,他们要等待被其他线程唤醒

    没有设置timeout参数的Object.wait()

    没有设置timeout参数的Thread.join()

    LockSupport.park()

    线程的有限期等待

    处于这种状态的线程也不会被CPU分配执行时间,不过不需要等待被其他线程显示的唤醒,在一定时间后他们会由系统自动唤醒

    Thread.sleep()方法

    设置了timeout的Object.wait()方法

    设置了timeout的Thread.join()方法

    LockSupport.parkNanos()方法

    LockSupport.parkUntil()方法

    线程阻塞和线程等待的区别

    阻塞是等待着获取一个锁对象的释放,进入阻塞是被动的,离开阻塞状态是因为其他线程释放了锁对象,自己获取到了执行权,就不阻塞了。(不受开发控制的,其他线程竞争到资源,自己就被迫被阻塞了)

    等待状态是在等待一段时间,或者唤醒动作的发生,进入等待状态是主动的。是自己进入的。

    线程结束

    run(),call()方法正常执行完,就是正常结束线程

    线程抛出一个未捕获的Exception或者Error,也会执行结束

    或者开发人员调用了stop()方法结束线程

    问题:start和run有什么区别?

    相关文章

      网友评论

        本文标题:【多线程】——2.线程的创建

        本文链接:https://www.haomeiwen.com/subject/fhtyuhtx.html