文章目录
进程和线程概念继承Thread 重写run方法实现Runnable 重写run方法(解耦合)通过匿名内部类lambda表达式线程的常见的属性(方法)Id(getId)名称(get Name)是否后台线程(isDaemon)是否存活(isAlive)
进程和线程概念
进程(process):进程是操作系统资源分配的基本单位
,操作系统目前包含多个进程而每个进程中包含着单个或者多个线程,一个进程由多个PCB(线程)来表示在代码中,如果进程出错后,不会影响到其他的进程的资源分配。重量级进程。
线程(Thread):是建立在进程之中进行任务调度和执行的基本单位
,轻量级进程。
在同一个进程内,线程在调度或者执行时如果遇到问题,可能会相互影响(线程的安全问题+线程出现异常)。
每一个线程都可以独立的区cpu区调度执行
在同一个进程的多个线程之间,共用着同一块内存空间和文件的资源(每个线程包含状态、优先级、上下文、记账信息…)。
当第一次创建线程时,只需要申请一次资源即可,然后直接服用之前已经分配给进程的资源,省去了资源分配的开销,这样效率会得到进一步提升。
如果一个进程中的线程数量过多时,效率可能无法提升,反而还会因为调度的线程过多,时调度的开销更大,反而会降低效率。
方法 | 说明 |
---|---|
Thread | 创建线程对象 |
Thread(Runnable) | 使用Runnable对象创建线程对象 |
Thread(String name) | 创建线程对象,并命名 |
Thread(Runnable target,String name) | 线程可以用来分组管理,分好的组即为线程组 |
继承Thread 重写run方法
当重写Thread方法时,run和start都是Thread的成员属性,run描述了线程的入口(线程要做的事情)start才是真正的调用了系统的API,在系统中创建出了线程,让线程在调用run。
这里的sleep属于static修饰的方法,通过类名进行调用
class MyThread extends Thread{ @Override public void run() { //这是线程的入口 while (true) { System.out.println("hello thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }}public class Demo1 { public static void main(String[] args) { MyThread myThread=new MyThread();//创建线程实例 myThread.start();//进入线程 //这是主线程 while(true){ System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }}
实现Runnable 重写run方法(解耦合)
通过MyRunnable 来实现Runnable方法来重写run方法,通过在main方法中实例化MyRunnable 来作为参数传给Thread,然后通过start调用API,然后通过线程调用run方法.
class MyRunnable implements Runnable { @Override public void run() { while (true) { System.out.println("hello thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }}public class Demo2 { public static void main(String[] args) { Runnable runnable=new MyRunnable(); Thread t=new Thread(runnable); t.start(); while(true){ System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }}
通过匿名内部类
无参构造重写run方法package Thread;public class Demo3 { public static void main(String[] args) { Thread thread=new Thread(){ @Override public void run() { while (true) { System.out.println("hello thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }; thread.start(); while(true){ System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }}
通过生成一个new Runnable来重写run方法
public class Demo4 { public static void main(String[] args) { Thread t=new Thread(new MyRunnable(){ @Override public void run() { while (true) { System.out.println("hello thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }); t.start(); while(true){ System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }}
lambda表达式
lamabda是一个匿名函数(执行一次就消失),主要用来实现“回调函数”的效果
回调函数:不是自身主动调用的,也不是现在就立即调用,而是将调用的机会交给操作系统,库,框架,别人写的代码。
而lambda的本质本质是一个函数氏接口(本身还是没有脱离类)。
package Thread;public class Demo5 { public static void main(String[] args) { Thread t=new Thread(()->{ while(true){ System.out.println("hello thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } },"new Thread");//定义的名字,通过java t.start(); while(true){ System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }}
在创建线程的时候,可以指定name来进行调试方便区分
这里的主线程的入口方法如果结束,则主线程销毁,只要代码执行完,则主线程销毁,参考下⬇️
线程的常见的属性(方法)
属性 | 获取方法 |
---|---|
ID | getId() |
名称 | get Name() |
状态 | getState() |
优先级 | getPriority() |
是否后台线程(默认为false) | isDaemon() |
是否存活 | isAlive() |
是否被终端 | isInterrupted() |
Id(getId)
线程的身份标识,类似于PID,标记一个进程中唯一的线程,是java提供的id,而不是API或者PCB提供的id。
名称(get Name)
获取在调试中方便观察的线程对象。
是否后台线程(isDaemon)
前台线程和后台线程(守护线程)默认为前台线程
在java进程中,前台线程中没有执行结束此时整个进程一定不结束。
相比之下,后台进程不结束,则不影响整个进程的结束。
public class Demo6 { public static void main(String[] args) { Thread thread=new Thread(()->{ while(true) { System.out.println("hello thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); //设置thread为后台线程 thread.setDaemon(true); thread.start(); }}
是否存活(isAlive)
查看线程是否存活,以boolean为类型
public static void main(String[] args) { Thread thread=new Thread(()->{ System.out.println("线程开始"); try { Thread.sleep(2000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("线程结束"); }); System.out.println(thread.isAlive()); thread.start(); //线程并发执行,并发调度的顺序不确定,取决于系统的调度器,因为调用start的时候,新线程的创建是需要开销时间的,当在创建过程中,大概率可能就会先打印第二个Alive。 System.out.println(thread.isAlive()); try { Thread.sleep(3000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(thread.isAlive()); }}