Java面试总结(六)
创始人
2024-06-01 13:32:33
0

进程和线程的区别

根本区别: 进程时操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。

资源开销: 每个进程都有自己独立的代码和数据空间(程序上下文),进程之间的切换开销比较大;线程可以看作轻量级进程,同类的线程共享进程的堆和方法区(JDK1.7及之前实现为永久代,JDK1.8及之后实现为元空间)资源,但是每个线程都有自己的程序计数器、Java虚拟机栈和本地方法栈,线程之间的切换开销比较小。

包含关系: 如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。

内存分配: 同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的。

影响关系: 一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉,所以多进程要比多线程健壮。

执行过程: 每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行。

总结: 线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。线程执行开销小,但不利于资源的管理和保护;而进程正相反。

创建线程的三种方式

使用继承Thread类的方式创建多线程

Thread类是Java提供的线程顶级类,继承Thread类可快速定义线程。

  • 使用多线程实现龟兔赛跑
public class TortoiseThread extends Thread{@Overridepublic void run() {while (true) {System.out.println("乌龟领先了,加油.....," +"当前线程的名称:" + this.getName() +",当前线程的优先级别:" + this.getPriority());}}public static void main(String[] args) {TortoiseThread tortoiseThread = new TortoiseThread();tortoiseThread.setName("乌龟线程");tortoiseThread.start();Thread.currentThread().setName("兔子线程");while(true){System.out.println("兔子领先了,add oil....,当前线程名称:"+Thread.currentThread().getName()+",当前线程的优先级别:"+Thread.currentThread().getPriority());}}
}
  • 运行结果截取(这里只截取了部分结果,应该是无限循环的)
乌龟领先了,加油.....,当前线程的名称:乌龟线程,当前线程的优先级别:5
乌龟领先了,加油.....,当前线程的名称:乌龟线程,当前线程的优先级别:5
兔子领先了,add oil....,当前线程名称:兔子线程,当前线程的优先级别:5
兔子领先了,add oil....,当前线程名称:兔子线程,当前线程的优先级别:5

使用实现Runnable接口的方式创建多线程

  • 使用多线程实现龟兔赛跑
public class TortoiseRunnable implements Runnable{@Overridepublic void run() {while (true) {System.out.println("乌龟领先了,加油.....," +"当前线程的名称:" + Thread.currentThread().getName() +",当前线程的优先级别:" + Thread.currentThread().getPriority());}}public static void main(String[] args) {Thread thread = new Thread(new TortoiseRunnable());thread.setName("乌龟线程");thread.start();Thread.currentThread().setName("兔子线程");while(true){System.out.println("兔子领先了,add oil....,当前线程名称:"+Thread.currentThread().getName()+",当前线程的优先级别:"+Thread.currentThread().getPriority());}}
}
  • 运行结果截取(这里只截取了部分结果,应该是无限循环的)
乌龟领先了,加油.....,当前线程的名称:乌龟线程,当前线程的优先级别:5
乌龟领先了,加油.....,当前线程的名称:乌龟线程,当前线程的优先级别:5
兔子领先了,add oil....,当前线程名称:兔子线程,当前线程的优先级别:5
兔子领先了,add oil....,当前线程名称:兔子线程,当前线程的优先级别:5

使用实现Callable接口的方式创建多线程

  • 使用多线程实现龟兔赛跑
public class TortoiseCallable implements Callable {@Overridepublic Object call() throws Exception {while (true) {System.out.println("乌龟领先了,加油.....," +"当前线程的名称:" + Thread.currentThread().getName() +",当前线程的优先级别:" + Thread.currentThread().getPriority());}}public static void main(String[] args) {TortoiseCallable tortoiseCallable = new TortoiseCallable();FutureTask futureTask = new FutureTask(tortoiseCallable);Thread thread = new Thread(futureTask);thread.setName("乌龟线程");thread.start();Thread.currentThread().setName("兔子线程");while(true){System.out.println("兔子领先了,add oil....,当前线程名称:"+Thread.currentThread().getName()+",当前线程的优先级别:"+Thread.currentThread().getPriority());}}
}
  • 运行结果截取(这里只截取了部分结果,应该是无限循环的)
乌龟领先了,加油.....,当前线程的名称:乌龟线程,当前线程的优先级别:5
乌龟领先了,加油.....,当前线程的名称:乌龟线程,当前线程的优先级别:5
兔子领先了,add oil....,当前线程名称:兔子线程,当前线程的优先级别:5
兔子领先了,add oil....,当前线程名称:兔子线程,当前线程的优先级别:5

创建三种线程的方式对比

使用实现Runnable、Callable接口的方式创建多线程。

  • 优势:
    Java的设计是单继承的设计,如果使用继承Thread的方式实现多线程,则不能继承其他的类,而如果使用实现Runnable接口或Callable接口的方式实现多线程,还可以继承其他类。
    采用接口能够更好的实现数据共享。线程的启动需要Thread类的start方法,如果采用继承的方式每次新建一个线程时,每个新建线程的数据都会单独的存在线程内存中,这样每个线程会单独的操作自己线程的数据,不能更好的实现线程之间的数据共享。

  • 劣势:
    编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。

使用继承Thread类的方式创建多线程

  • 优势:
    编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。

  • 劣势:
    线程类已经继承了Thread类,所以不能再继承其他的类。

Runnable和Callable的区别

与Runnable相比,Callable功能更强大些

  • Callable规定(重写)的方法是call(),Runnable规定(重写)的方法是run()。
  • Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
  • call方法可以抛出异常,run方法不可以。
  • Callable是支持泛型的
  • 运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。

Runnable接口源码

@FunctionalInterface
public interface Runnable {public abstract void run();
}

Callable接口源码

@FunctionalInterface
public interface Callable {/*** Computes a result, or throws an exception if unable to do so.** @return computed result //可以有返回值* @throws Exception if unable to compute a result  //可以抛出异常*/V call() throws Exception;
}

Callable接口使用案例

/*
创建线程的方式三:实现Callable接口。-----JDK1.5新增*/
//1.创建一个实现Callable的实现类
class NumThread implements Callable{//2.实现call方法,将此线程需要执行的操作声明在call()中@Overridepublic  Object call() throws Exception{int sum=0;for (int i=1;i<=100;i++){sum+=i;}return sum;}
}
public class ThreadNew {public static void main(String[] args) throws ExecutionException, InterruptedException {//3.创建Callable接口实现类的对象NumThread numThread=new NumThread();//4.将此Callable接口实现类的对象作为传递到FutureTask构造中,创建FutureTask的对象FutureTask futureTask=new FutureTask(numThread);//5.将FutureTask的对象组排位哦参数传递到thread类的构造器中,创建Thread对象,并调用start()new Thread(futureTask).start();//6.获取Callable中call方法的返回值//get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值Object sum = futureTask.get();System.out.println("总和为:"+sum);}
}

线程的状态

  1. NEW:初始状态,线程刚刚被创建出来,还没有调用 start() 方法;
  2. RUNABLE:运行中状态,调用了 start() 方法,Java 线程将操作系统中的 就绪/可运行(READY)状态和 运行(RUNNING)状态统称为 RUNABLE 状态;
  3. BLOCK:阻塞状态,线程阻塞于锁,需要等待锁的释放;
  4. WAITING:等待状态,进入等待状态表示需要等待其他线程做出一些特定的状态(通知或中断);
  5. TIMED_WAITING:超时等待状态,可以在指定时间后自行返回,而不是像WAITING状态一样一直等待;
  6. TEMENATED:终止状态,表示当前线程已经执行完毕。

在这里插入图片描述

  • 由上图可以看出:线程创建之后它将处于 NEW(初始) 状态,调用 start() 方法后开始运行,线程这时候处于 READY(就绪/可运行) 状态。可运行状态的线程获得了 CPU 时间片(timeslice)后就处于 RUNNING(运行) 状态。

  • 在操作系统层面,线程有 READY 和 RUNNING 状态;而在 JVM 层面,只能看到 RUNNABLE 状态,所以 Java 系统一般将这两个状态统称为 RUNNABLE(运行中) 状态 。

  • 为什么 JVM 没有区分这两种状态呢?
    java 现在的时分(time-sharing)多任务(multi-task)操作系统架构通常都是用所谓的“时间分片(time quantum or time slice)”方式进行抢占式(preemptive)轮转调度(round-robin 式)。这个时间分片通常是很小的,一个线程一次最多只能在 CPU 上运行比如 10-20ms 的时间(此时处于 running 状态),也即大概只有 0.01 秒这一量级,时间片用后就要被切换下来放入调度队列的末尾等待再次调度。(也即回到 ready 状态)。线程切换的如此之快,区分这两种状态就没什么意义了。

  • 当线程执行 wait()方法之后,线程进入 WAITING(等待) 状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到运行状态。

  • TIMED_WAITING(超时等待) 状态相当于在等待状态的基础上增加了超时限制,比如通过 sleep(long millis)方法或 wait(long millis)方法可以将线程置于 TIMED_WAITING 状态。当超时时间结束后,线程将会返回到 RUNNABLE 状态。

  • 当线程进入 synchronized 方法/块或者调用 wait 后,(被 notify)想要重新进入 synchronized 方法/块时,但是锁被其它线程占有,这个时候线程就会进入 BLOCKED(阻塞) 状态。

  • 线程在执行完了 run()方法之后将会进入到 TERMINATED(终止) 状态。

相关内容

热门资讯

安卓如何检测系统广播,Andr... 你有没有想过,你的安卓手机里那些神奇的“广播”是怎么工作的呢?没错,就是那些悄无声息地在你手机后台运...
安卓系统怎么刷recovery... 你有没有想过,你的安卓手机突然间变得有点儿不听话了?别急,别急,我来告诉你怎么刷recovery,让...
不用安卓和苹果系统,多元化移动... 你有没有想过,在这个科技飞速发展的时代,我们竟然可以不用安卓和苹果系统,也能畅游网络世界呢?没错,今...
安卓系统忘记网络设置,安卓系统... 亲爱的安卓用户们,你是否曾经遇到过这样的烦恼:手机连接网络时,突然忘记了网络设置,各种网络连接问题层...
安卓系统无法自己升级,自主升级... 你是不是也遇到了这个问题?安卓系统怎么就突然不升级了呢?别急,今天就来给你好好捋一捋这个让人头疼的小...
华为变成原生安卓系统,原生安卓... 你知道吗?最近科技圈可是炸开了锅,华为的大动作让所有人都瞪大了眼睛。没错,就是那个我们熟悉的华为,竟...
安卓系统手机很便宜,高性价比的... 你有没有发现,最近逛手机市场,安卓系统手机的价格真是让人惊喜不已呢!没错,就是那种我们平时用的最多的...
原生的安卓系统 索尼,深度解析... 你知道吗?在智能手机的世界里,有一个品牌总是以其独特的魅力和精湛的工艺吸引着众多科技爱好者。那就是索...
安卓系统更新历史,从初代到最新... 你有没有发现,你的安卓手机每次更新后都变得焕然一新?没错,这就是安卓系统更新带来的魔力!今天,就让我...
安卓系统的第二套系统,创新与变... 你知道吗?在科技飞速发展的今天,安卓系统已经成为了智能手机市场上的霸主。但是,你知道吗?安卓系统其实...
全军出击安卓系统版本,战力再攀... 你有没有发现,最近全军出击这款游戏在安卓系统上的版本更新可是越来越频繁了呢?这不,我就来给你好好扒一...
安卓系统热点限速软件,优化热点... 你有没有遇到过这种情况:手机连接热点后,网速就像蜗牛爬行一样慢,简直让人抓狂!别急,今天就来给你揭秘...
安卓系统占内存多,揭秘内存消耗... 你有没有发现,手机用着用着,内存就不够用了?尤其是安卓系统,好像特别能吃内存,让人头疼不已。今天,就...
最近安卓系统奔溃,揭秘原因与应... 最近手机界可是炸开了锅呢!安卓系统竟然出现了大规模奔溃,这可真是让人摸不着头脑。咱们一起来探究这背后...
ce系统能刷安卓系统吗,揭秘能... 你有没有想过,你的安卓手机是不是也能用上CE系统呢?这可不是天方夜谭,今天就来给你揭秘一下这个神秘的...
安卓系统UI设计特色,创新与用... 你有没有发现,每次打开安卓手机,那界面设计得真是让人眼前一亮呢?今天,就让我带你一起探索一下安卓系统...
ipod有安卓系统吗,跨界融合... 你有没有想过,那个曾经风靡一时的iPod,它到底有没有安卓系统呢?这个问题,估计让不少音乐爱好者都好...
安卓多少系统最高的,揭秘最高版... 你有没有想过,你的安卓手机到底升级到了哪个系统版本呢?是不是好奇安卓系统里哪个版本才是最高级的呢?别...
现在安卓最高的系统,揭秘安卓1... 你有没有发现,手机更新换代的速度简直就像坐上了火箭呢!这不,最近安卓系统又来了一次大升级,听说这是现...
安卓系统怎么隐藏相册,安卓系统... 你是不是也有那么几本“私人珍藏”,不想让旁人随意翻看呢?比如,手机里的相册,里面藏着我们的喜怒哀乐,...