首页 > 作文

详解Java创建线程的五种常见方式

更新时间:2023-04-04 19:30:05 阅读: 评论:0

目录
java中如何创建线程呢?1.显示继承thread,重写run来指定现成的执行代码。2.匿名内部类继承thread,重写run来执行线程执行的代码。3.显示实现runnable接口,重写run方法。4.匿名内部类实现runnable接口,重写run方法5.通过lambda表达式来描述线程执行的代码【面试题】:thread的run和start之间的区别?thread类的具体用法thread类常见的一些属性中断一个线程1.方法一:让线程run完2.方法二:调用interrupted()方法线程等待线程休眠线程的状态转换

java中如何进行多线程编程,如何使用多线程?在java标准库中提供了一个thread类。java中,一个进程正在运行时至少会有一个线程正在运行,这些线程在后台默默地执行,比如调用main()方法时就是这样的,主线程是由jvm创建的。实现多线程编程的方式主要有两种,一是继承thread类,另一种是实现runnable接口。这里我们先来看看thread类的结构:

从源代码中可以发现,thread类实现了runnable接口,它们之间具有多态关系。其实,使用继承thread类的方式创建新线程是,最大的局限就是不支持多继承,因为在java语言特点就是单继承,所以为了支持多继承,完全可以实现runnable接口的方式。

java中如何创建线程呢?

1.显示继承thread,重写run来指定现成的执行代码。

代码

public class demo1 {  static class mythread extends thread {    @override    public void run() {      system.out.println("hello world, 我是一个线程");      while (true) {      }    }  }  public static void main(string[] args) {    // 创建线程需要使用 thread 类, 来创建一个 thread 的实例.    // 另一方面还需要给这个线程指定, 要执行哪些指令/代码.    // 指定指令的方式有很多种方式, 此处先用一种简单的, 直接继承 thread 类,    // 重写 thread 类中的 run 方法.    // [注意!] 当 thread 对象被创建出来的时候, 内核中并没有随之产生一个线程(pcb).    thread t = new mythread();    t.start();    // 执行这个 start 方法, 才是真的创建出了一个线程.    // 此时内核中才随之出现了一个 pcb, 这个 pcb 就会对应让 cpu 来执行该线程的代码. (上面的 run 方法中的逻辑)       while (true) {      // 这里啥都不干    }  }}

2.匿名内部类继承thread,重写run来执行线程执行的代码。

代码

public class demo2 {  // runnable 本质上就是描述了一段要执行的任务代码是啥.  static class myrunnable implements runnable {    @override    public void run() {      system.out.println("我是一个新线程");    }  }  public static void main(string[] args) {    // 2. 通过匿名内部类的方式继承 thread    thread t = new thread() {      @override      public void run() {      }    };    t.start(); }

3.显示实现runnable接口,重写run方法。

代码

public class demo3 {  // runnable 本质上就是描述了一段要执行的任务代码是啥.  static class myrunnable implements runnable {    @override    public void run() {      system.out.println("我是一个新线程");    }  }  public static void main(string[] args) {    // 3. 显式创建一个类, 实现 runnable 接口, 然后把这个 runnable 的实例关联到 thread 实例上.    thread t = new thread(new myrunnable());    t.start(); }

4.匿名内部类实现runnable接口,重写run方法

代码

public class demo4 {  // runnable 本质上就是描述了一段要执行的任务代码是啥.  static class myrunnable implements runnable {    @override    public void run() {      system.out.println("我是一个新线程");    }  }  public static void main(string[] args) {    // 4. 通过匿名内部类来实现 runnable 接口    runnable runnable = new runnable() {      @override      public void run() {        system.out.println("我是一个新线程");      }    };    thread t = new thread(runnable);    t.start(); }

5.通过lambda表达式来描述线程执行的代码

代码

public class demo4 {  // runnable 本质上就是描述了一段要执行的任务代码是啥.  static class myrunnable implements runnable {    @override    public void run() {      system.out.println("我是一个新线程");    }  }  public static void main(string[] args) {    // 5. 使用 lambda 表达式来指定 线程执行的内容    thread t = new thread(() -> {      sy湖南一本stem.out.println("我是一个新线程");    });    t.start(); }

【面试题】:thread的run和start之间的区别?

run()方法::普通的方法调用,没有创建新的线程,输出语句是在原线程中执行的。

start()方法::这才是创建了一个新线程,由新的线程来执行输出

thread类的具体用法

thread类常见的一些属性

id是现成的唯一标识,不同线程不会重复

名称是各种调试工具会用到的

状态标识线程当前所处的一个情况

优先级高的线程理论上来说更容易被调度到

关于后台先后曾,需要记住一点:jvm会在一个进程的所有非后台线程结束后,才会结束运行

是否存活,即run方法是否运行结束了

线程的中断问题

我们通过编写具体的代码来观察方法的使用:

public class threaddemo6 {  public static void main(string[] args) {    thread t=new thread("cxk"){      @override      public void run() {        for (int i = 0; i &e的负x次方lt; 10; i++) {          system.out.println(thread.currentthread().getname());          try {            thread.sleep(1000);          } catch (interruptedexception e) {            e.printstacktrace();          }        }      }    };    //run方法执行过程中就代表着系统内线程得生命周期    //润方法执行中,内核的线程就存在    //run方法执行完毕,内核中的线程随之销毁    //这一组属性,只要线程创建完毕,属性就变了    system.out.println(t.getname());    system.out.println(t.getpriority());    system.out.println(t.isdaemon());    system.out.println(t.getid());    //这俩属性会随着现成的运行过程而发生改变    system.out.println(t.isalive());    system.out.println(t.isinterrupted());    system.out.println(t.getstate());    t.start();    while (t.isalive()){      system.out.println("cxk线程正在执行");      system.out.println(t.isinterrupted());      system.out.println(t.getstate());    }  }}

执行结果如下:会出现很多组相同的数据

中断一个线程

让一个线程结束有两种情况:

1.此线程已经把任务执行完了。即让线程run完(比较温和)。

2.此线程将任务执行到一半,被强制结束。即调用线程的interrupt()方法,比较激烈。

1.方法一:让线程run完

这种结束方式比较温和,当标记位被设置上之后,等到这次循环执行完了之后,在结束线程,如下,当线程执行到sleep的时候,已经sleep100ms了,此时isquit被设置为true,当前线程不会立即退出,而是会继续sleep,把剩下的 400ms sleep完才会结束这个线程。

public class threaddemo7 {  private static boolean isquit=fal;  public static void main(string[] args) throws interruptedexception {    thread t=new thread(){      @override      public void run() {        while (!isquit){          system.out.println("别烦我,我在忙着转账呢");          try {            thread.sleep(500);          } catch (interruptedexception e) {            e.printstacktrace();          }        }        system.out.println("转账操作被终止");      }    };    t.start();    thread.sleep(500);    //老板来电话了说对方是内鬼终止交易    system.out.println("有内鬼,终止交易!!!");    isquit = true;  }}

执行结果:

2.方法二:调用interrupted()方法

public class threaddemo8 {  public static void main(string[] args) throws interruptedexception {    thread t = new thread() {      @override      public void run() {        // 此处直接使用线程内部的标记位来判定.        while (!thread.currentthread().isinterrupted()) {          system.out.println("别管我, 我在忙着转账呢");          try {            thread.sleep(500);          } catch (interruptedexception e) {            e.printstacktrace();            break;          }        }        system.out.println("转账被终止.");      }    };    t.start();    thread.sleep(5000);    system.out.println("对方是内鬼, 快终止交易!!!");    t.interrupt();  }}

执行结果如下:

在这段代码中,t.start()是主线程继续往下执行之后,主线程还是会继续走,新线程则会执行run方法,如果没有后续的sleep,新线程能否继续输出就是不确定的了。原因:多线程之间是抢占实质性的,如果主线程中没有sleep,此时接下来cpu是执行主现成的isquit=true还是新线程的while循环,这都是不确定的。对于新线程来说,run方法执行完,线程就结束了。对于主线程来说main方法执行完,住线程就结束了。

由上可得:

1.通过thread对象调用interrupt()方法别董大的诗意通知该线程停止运行。

2.thread收到通知的方式有两种:

如果线程调用了wait/join/sleep等方法而阻塞挂起,则以interrupterexception异常的形式通知,清除中断标志

如果没有调用上述方式,就只是内部的一个中断标志被设置,thread可以通过thread.interrupted()判断当前线程的中断标志被设置,来清除中断标志。也可以

使用thread.currentthread().isinterrupted()判断指定线程的中断标志被设置,但是不会清除中断标志。

在java中第二种方式通知收到的更及时,即使线程正在sleep也可以马上收到。

public class threaddemo10 {    public static void main(string[] args) {        thread t=new thread(){            @override            public void run() {                for (int i = 0; i < 10; i++) {                    system.out.println(thread.currentthread().isinterrupted());                    //仅仅是判定标记位,不会修改标记位                }            }        };        t.好看的篮球小说start();        t.interrupt();    }}
public class threaddemo11 {    public static void main(string[] args) throws interruptedexception {        thread t=new thread(){            @override            public void run() {                system.out.println("我是新线程");                try {                    thread.sleep(3000);                } catch (interruptedexception e) {                    e.printstacktrace();                }            }        };        t.start();        while (true){            system.out.println("我是主线程");            thread.sleep(1000);            //对于新线程来说,run方法执行完新线程就结束了,            //对于主线程来说,main方法执行完主线程就结束了        }    }}

线程等待

线程之间是并发执行的关系,多个线程之间,谁先执行,谁后执行,谁执行到何处让出cpu…开发人员是完全无法感知的,全权由系统内核负责,例如,创建一个新线程的时候,此时接下来是主线程继续执行,还是新线程执行,这个事情是不能保证的,这就是“抢占式”执行的重要特点。这时候就引入了线程等待:开发人员可以控制哪个线程先结束,哪个线程后结束。join()方法的执行就会让线程阻塞,一直阻塞到对应线程执行结束之后,才会继续执行。这就可以控制线程结束的先后顺序。如果线程结束了才调用到join,此时也会立刻返回。

public class threaddemo12 {    public static void main(string[] args) throws interruptedexception {        thread t1=new thread(){            @override            public void run() {                for (int i = 0; i < 10; i++) {                    system.out.println("我是线程1");                    try {                        thread.sleep(3000);                    } catch (interruptedexception e) {                        e.printstacktrace();                    }                }            }        };        thread t2=new thread(){            @override            public void run() {                for (int i = 0; i < 10; i++) {                    system.out.println("我是线程2");                    try {                        thread.sleep(3000);                    } catch (interruptedexception e) {                        e.printstacktrace();                    }                }            }        };        t1.start();        t2.start();        t1.join();// join 起到的效果是等待线程结束. 当执行到这行代码是, 程序就阻塞了. 一直阻塞到 t1 结束, 才会继续执行.        t2.join();        system.out.println("主线程执行完毕");    }}

执行结果如下:

线程休眠

当线程在正常运行计算判断逻辑此时就是在就绪队列中排队,调度器就会从就绪队列中筛选出合适的pcb让他上cpu执行,如果某个线程调用sleep就会让对应的线程pcb进入到阻塞队列,线程一旦进入到了阻塞队列是没有办法上cpu执行的,对于sleep进入冷宫的时间是有限制勾股定理算法的,时间到了之后,就自动被系统把这个pcb那回到原来的就绪队列中了。

线程的状态转换

以上就是详解java创建线程的五种常见方式的详细内容,更多关于java创建线程的资料请关注www.887551.com其它相关文章!

本文发布于:2023-04-04 19:30:03,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/80c40d12aa783dc038d52d9787789620.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:详解Java创建线程的五种常见方式.doc

本文 PDF 下载地址:详解Java创建线程的五种常见方式.pdf

标签:线程   方法   代码   主线
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图