java多线程专项(进程和线程的区别)

进程和线程的区别

线程和进程的区别是什么?(知乎)
一道面试题:说说进程和线程的区别
进程和线程的区别
每个程序员都会遇到的面试问题:谈谈进程和线程的区别(用车间工人类比很形象地说明进程与线程的区别)
进程线程面试题总结
[面试] 进程和线程的区别(面试题)

c++面试题(线程与进程篇)
多线程面试题(墙裂推荐)
多进程和多线程的概念
线程和进程有什么区别(简单介绍)

分点回答(面试时需要逻辑条理清晰、语言简洁、直中要害)

(1)进程

进程是程序的一次执行过程,是一个动态概念,是程序在执行过程中分配和管理资源的基本单位,每一个进程都有一个自己的地址空间,至少有 5 种基本状态,它们是:初始态,执行态,等待状态,就绪状态,终止状态。

(2)线程

线程是CPU调度和分派的基本单位,它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
(3)联系

线程是进程的一部分,一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
(4)区别:
理解它们的差别,我从资源使用的角度出发。(所谓的资源就是计算机里的中央处理器,内存,文件,网络等等)

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

在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。

所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)

内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。

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

那么执行与调度的基本单位是线程,这样设置有什么好处?

计算机操作系统里面有两个重要概念:并发和隔离。
并发是为了尽量让硬件利用率高,线程是为了在系统层面做到并发。线程上下文切换效率比进程上下文切换会高很多,这样可以提高并发效率。

隔离也是并发之后要解决的重要问题,计算机的资源一般是共享的,隔离要能保障崩溃了这些资源能够被回收,不影响其他代码的使用。所以说一个操作系统只有线程没有进程也是可以的,只是这样的系统会经常崩溃而已,操作系统刚开始发展的时候和这种情形很像。

所以:线程和并发有关系,进程和隔离有关系。线程基本是为了代码并发执行引入的概念,因为要分配cpu时间片,暂停后再恢复要能够继续和没暂停一样继续执行;进程相当于一堆线程加上线程执行过程中申请的资源,一旦挂了,这些资源都要能回收,不影响其他程序。

“互斥锁”(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。

操作系统的设计,因此可以归结为三点:

(1)以多进程形式,允许多个任务同时运行;

(2)以多线程形式,允许单个任务分成不同的部分运行;

(3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。

进程和线程

进程==是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。程序运行时系统就会创建一个进程,并为它分配资源,进程:指在系统中正在运行的一个应用程序;程序一旦运行就是进程;或者更专业化来说:进程是指程序执行时的一个实例

线程:系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。进程——资源分配的最小单位,线程——程序执行的最小单位。

进程是资源分配的最小单位,线程是程序执行的最小单位。

区别

因为线程是共享进程的资源的,所以栈是私有的,堆是公有的

因为进程拥有独立的堆栈空间和数据段,所以每当启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这对于多进程来说十分“奢侈”,系统开销比较大,而线程不一样,线程拥有独立的堆栈空间,但是共享数据段,它们彼此之间使用相同的地址空间,共享大部分数据,比进程更节俭,开销比较小,切换速度也比进程快,效率高,但是正由于进程之间独立的特点,使得进程安全性比较高,也因为进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。一个线程死掉就等于整个进程死掉。

进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。

通信机制上面,正因为进程之间互不干扰,相互独立,进程的通信机制相对很复杂,譬如管道,信号,消息队列,共享内存,套接字等通信机制,而线程由于共享数据段所以通信机制很方便

线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行

在CPU系统上面,线程使得CPU系统更加有效,因为操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上

多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间

1、进程是资源分配最小单位,线程是程序执行的最小单位;
2、进程有自己独立的地址空间,每启动一个进程,系统都会为其分配地址空间,建立数据表来维护代码段、堆栈段和数据段,线程没有独立的地址空间,它使用相同的地址空间共享数据;
3、CPU切换一个线程比切换进程花费小;
4、创建一个线程比进程开销小;
5、线程占用的资源要⽐进程少很多。
6、线程之间通信更方便,同一个进程下,线程共享全局变量,静态变量等数据,进程之间的通信需要以通信的方式(IPC)进行;(但多线程程序处理好同步与互斥是个难点)
7、多进程程序更安全,生命力更强,一个进程死掉不会对另一个进程造成影响(源于有独立的地址空间),多线程程序更不易维护,一个线程死掉,整个进程就死掉了(因为共享地址空间);
8、进程对资源保护要求高,开销大,效率相对较低,线程资源保护要求不高,但开销小,效率高,可频繁切换;

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

什么情况下使用进程和线程:

1、需要频繁创建销毁的优先使用线程;因为对进程来说创建和销毁一个进程代价是很大的
2、线程的切换速度快,所以在需要大量计算,切换频繁时用线程,还有耗时的操作使用线程可提高应用程序的响应
3、因为对CPU系统的效率使用上线程更占优,所以可能要发展到多机分布的用进程,多核分布用线程
4、并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求
5、需要更稳定安全时,适合选择进程;需要速度时,选择线程更好

进程和线程的关系

1、一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程是操作系统可识别的最小执行和调度单位。
2、资源分配给进程,同一进程的所有线程共享该进程的所有资源。 同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)。但是每个线程拥有自己的栈段,栈段又叫运行时段,用来存放所有局部变量和临时变量。
3、处理机分给线程,即真正在处理机上运行的是线程。
4、线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。

多线程一般用在哪些地方?

1、java多线程一般多用于高并发的地方,如订单状态的修改,可以通过多线程,固定时间执行修改订单状态,还有就是支付方面一般都会用到多线程。
2、如果不采用多线程机制,上百个人同时访问一个web应用的时候,tomcat就得排队串行处理了,那样客户端根本是无法忍受那种访问速度的。
4、特别耗时的操作,如备份数据库,可以开个线程执行备份,然后执行返回,前台不断向后台询问线程执行状态
总之使用多线程就是为了充分利用cpu的资源,提高程序执行效率,当你发现一个业务逻辑执行效率特别低,耗时特别长,就可以考虑使用多线程。不过CPU执行哪个线程的时间和顺序是不确定的,即使设置了线程的优先级,因此使用多线程

多线程的优点?

1、使用线程可以把占据时间长的程序中的任务放到后台去处理
2、用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
3、程序的运行速度可能加快
4、在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下可以释放一些珍贵的资源如内存占用等等。
5、多个线程交替执行,减少或避免因程序阻塞或意外情况造成的响应过慢现象,降低了用户等待的概率。

多线程的缺点?

1、如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换。
2、更多的线程需要更多的内存空间。
3、程可能会给程序带来更多“bug”,因此要小心使用
4、线程的中止需要考虑其对程序运行的影响。
5、通常块模型数据是在多个线程间共享的,需要防止线程死锁情况的发生。

举个例子:

开个QQ,开了一个进程;开了迅雷,开了一个进程。在QQ的这个进程里,传输文字开一个线程、传输语音开了一个线程、弹出对话框又开了一个线程。所以运行某个软件,相当于开了一个进程。在这个软件运行的过程里(在这个进程里),多个工作支撑的完成QQ的运行,那么这“多个工作”分别有一个线程。所以一个进程管着多个线程。通俗的讲:“进程是爹妈,管着众多的线程儿子”…

线程池的概念

线程池就是一堆已经创建好的线程,最大数目一定,然后初始后都处于空闲状态,当有新任务进来时就从线程池中取出空闲线程处理任务,任务完成之后又重新放回去,当线程池中的所有线程都在任务时,只能等待有线程结束任务才能继续执行

run()和start()

run()相当于线程的任务处理逻辑的入口方法,它由Java虚拟机在运行相应线程时直接调用,而不是由应用代码进行调用。

而start()的作用是启动相应的线程。启动一个线程实际是请求Java虚拟机运行相应的线程,而这个线程何时能够运行是由线程调度器决定的。start()调用结束并不表示相应线程已经开始运行,这个线程可能稍后运行,也可能永远也不会运行。
run方法线程执行体.start方法开启多线程

实现多线程的方法

1.继承Thread类
2.实现Runnable接口
3.实现Callable接口

实现多线程的方法:
1.继承Thread类
2.实现Runnable接口
3.实现Callable接口,然后使用 FutureTask包装,因为Callable接口没有实现Runnable接口不能做为Thread的target,而FutureTask是在Java程序中可以取消的异步运算,有可以开始,取消运算,查询运算是否结束,获得查询结果的功能,特别注意的是,如果查询结果时,运算还没完成则会阻塞线程。
4.使用,java.util.current.ThreadPoolExecutor来获取线程,执行多线程

Java多线程实现方式主要有四种:继承Thread类、实现Runnable接口、实现Callable接口通过FutureTask包装器来创建Thread线程、使用ExecutorService、Callable、Future实现有返回结果的多线程。

其中前两种方式线程执行完后都没有返回值,后两种是带返回值的。

一些选择题

1 下列说法正确的是(BD)?

我们直接调用Thread对象的run方法会报异常,所以我们应该使用start方法来开启一个线程

一个进程是一个独立的运行环境,可以被看做一个程序或者一个应用。而线程是在进程中执行的一个任务。Java运行环境是一个包含了不同的类和程序的单一进程。线程可以被称为轻量级进程。线程需要较少的资源来创建和驻留在进程中,并且可以共享进程中的资源

synchronized可以解决可见性问题,volatile可以解决原子性问题

ThreadLocal用于创建线程的本地变量,该变量是线程之间不共享的

A:可以直接调用run方法, 但就起不到多线程的目的了。
volatile与synchronized的区别:
volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住.
volatile仅能使用在变量级别,synchronized则可以使用在变量,方法.
volatile仅能实现变量的修改可见性,但不具备原子特性,而synchronized则可以保证变量的修改可见性和原子性.
volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞.
volatile标记的变量不会被编译器优化,而synchronized标记的变量可以被编译器优化.

2 以下多线程对int型变量x的操作,哪个不需要进行同步(D)

++x

x=y

x++

x=1

同步是害怕在操作过程的时候被其他线程也进行读取操作,一旦是原子性的操作就不会发生这种情况因为一步到位的操作,其他线程不可能在中间干涉。另外三项都有读取、操作两个步骤,而X=1则是原子性操作。

前三个都至少需要先读取,再操作,非原子操作。而D的话,直接赋值。

ABC不是原子性操作,例如想x++,先获取x的值,自增一,然后再把值赋给x,三步,中间任何一步执行时都可能被其他线程访问或者修改。所以需要同步

3 执行以下程序,最终输出可能是: C

在这里插入图片描述

010 2123012 3434

01201 340124 2334

0012314 01223344**

12345 12345 12345

每个线程输出0,1,2,3,4,’空格, 输出空格前必有线程输出了0-4,所以选C、

虽然每次结果不同,但是第一个空格之前必然有 0 1 2 3 4 这四个数字,这是因为第一个空格出现,意味着第一个线程执行完毕,必然会打印这四个数字。又因为线程并发执行,所以后面两个线程个别数字可能会提前打印,这就导致了答案有很多。

三个线程是并发执行的,所以三个线程各自的执行顺序必须是01234就是正确的,很容易得出是C答案
在这里插入图片描述
4 以下程序运行的结果为 (A )

 public class Example extends Thread{
    
    

@Override

    public void run(){
    
    

        try {
    
    

            Thread.sleep(1000);

        } catch (InterruptedException e){
    
    

            e.printStackTrace();

        }

        System. out .print( "run" );

    }

    public static void main(String[] args){
    
    

        Example example= new Example();

        example.run();

        System. out .print( "main" );
    }
} 
run main

main run

main

run

不能确定

因为Example的run方法里面休眠了100ms,在当今电脑计算性能过剩的时代,如果是多线程启动,main方法肯定会打印出了main。

为啥是runmain而不是mainrun呢?

因为启动线程是调用start方法。
把线程的run方法当普通方法,就直接用实例.run()执行就好了。

没有看到start。所以是普通方法调用。
所以选A。

选A。考察的run()方法作为普通方法的调用和通过线程start的启动调用的区别。对象.start()属于对线程的启动调用run()方法。
题目给出的example.run();是对象对普通方法的调用,所以由上到下依次执行输出:run main。

5 下面说法正确的是?(BC)



调用Thread的sleep()方法会释放锁,调用wait()方法不释放锁

一个线程调用yield方法,可以使具有相同优先级线程获得处理器

在Java中,高优先级的可运行的线程会抢占低优先级线程的资源

java中,线程可以调用yield方法使比自己低优先级的线程运行

还记得马老师说过,yiled方法属于高风亮节的行为,这个坑位我不上了,后面跟我同级别的先上厕所。这样比较好记!

sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复(线程回到就绪状态,请参考第66题中的线程状态转换图)。wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态

== yield()让当前正在运行的线程回到可运行状态,以允许具有相同优先级的其他线程获得运行的机会==。因此,使用yield()的目的是让具有相同优先级的线程之间能够适当的轮换执行。但是,实际中无法保证yield()达到让步的目的,因为,让步的线程可能被线程调度程序再次选中

6 下列哪些操作会使线程释放锁资源?BC

sleep()

wait()

join()

yield()

yield()不会释放锁,只是通知调度器自己可以让出cpu时间片,但只是建议,调度器也不一定采纳
1.sleep()方法

在指定时间内让当前正在执行的线程暂停执行,但不会释放“锁标志”。不推荐使用。

sleep()使当前线程进入阻塞状态,在指定时间内不会执行。

2.wait()方法

在其他线程调用对象的notify或notifyAll方法前,导致当前线程等待。线程会释放掉它所占有的“锁标志”,从而使别的线程有机会抢占该锁。

当前线程必须拥有当前对象锁。如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常。

唤醒当前对象锁的等待线程使用notify或notifyAll方法,也必须拥有相同的对象锁,否则也会抛出IllegalMonitorStateException异常。

waite()和notify()必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。

3.yield方法

暂停当前正在执行的线程对象。

yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。

yield()只能使同优先级或更高优先级的线程有执行的机会。

4.join方法

等待该线程终止。

等待调用join方法的线程结束,再继续执行。如:t.join();//主要用于等待t线程运行结束,若无此句,main则会执行完毕,导致结果不可预测。

==join()底层就是调用wait()方法的,wait()释放锁资源,故join也释放锁资源 ==
在这里插入图片描述

1.sleep会使当前线程睡眠指定时间,不释放锁
2.yield会使当前线程重回到可执行状态,等待cpu的调度,不释放锁
3.wait会使当前线程回到线程池中等待,释放锁,当被其他线程使用notify,notifyAll唤醒时进入可执行状态
4.当前线程调用 某线程.join()时会使当前线程等待某线程执行完毕再结束,底层调用了wait,释放锁

6 java中下面哪个能创建并启动线程(C)

public class MyRunnable implements Runnable          {
    
     
     public void run()             {
    
     
         //some code here 
     } 
 }
new Runnable(MyRunnable).start()

new Thread(MyRunnable).run()

new Thread(new MyRunnable()).start()

new MyRunnable().start()

首先:创建并启动线程的过程为:定义线程—》实例化线程—》启动线程。
一 、定义线程: 1、扩展java.lang.Thread类。 2、实现java.lang.Runnable接口。
二、实例化线程: 1、如果是扩展java.lang.Thread类的线程,则直接new即可。
2、如果是实现了java.lang.Runnable接口的类,则用Thread的构造方法:
Thread(Runnable target)
Thread(Runnable target, String name)
Thread(ThreadGroup group, Runnable target)
Thread(ThreadGroup group, Runnable target, String name)
Thread(ThreadGroup group, Runnable target, String name, long stackSize)
所以A、D的实例化线程错误。
三、启动线程: 在线程的Thread对象上调用start()方法,而不是run()或者别的方法。
所以B的启动线程方法错误。

线程可以驱动任务,这可以由Runnable接口来提供,把你想要任务执行的命令写到run()方法中;
当从Runnable导出一个类时,它必须具有run()方法,但是这个方法不会产生任何内在的线程能力,要实现线程行为,就要将任务显式附着到线程上。传统方式是将Runnable对象提交给一个Thread构造器。调用Thread对象的start()方法是该线程执行所必需的初始化操作,然后
调用Runnable的run()方法,以便在这个新线程中启动该任务。

7 java Thread中,run方法和start方法的区别,下面说法错误的是?B

通过调用Thread类的start()方法来启动一个线程,这时此线程是处于就绪状态,并没有运行。

他们都可以实现了多线程运行。

run方法是thread的一个普通方法调用。

调用start方法后,一旦得到cpu时间片,就开始执行run()方法。

两种方法的区别:
1.start方法
用 start方法来启动线程,是真正实现了多线程, 通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法。但要注意的是,此时无需等待run()方法执行完毕,即可继续执行下面的代码。所以run()方法并没有实现多线程。
2.run方法
run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码。

run()方法就是一个普通的方法,真正启动一个新线程的话是start()

run方法是线程内重写的一个方法,start一个线程后使得线程处于就绪状态,当jvm调用的时候,线程启动会运行run。run函数是线程里面的一个函数不是多线程的。

8 Which method you define as the starting point of new thread in a class from which n thread can be execution?B

public void start()

public void run()

public void int()

public static void main(String args[])

public void runnable()

我的翻译:下面哪一个是你类中定义可以作为新线程的起始点,直到线程n被执行完毕的方法 ?
其实就是在问,线程执行的入口,start()是启动该线程的方法,是启动的动作
继承Thead,重写run方法或者实现Runable接口,实现run方法,run方法就是线程执行的入口

9 以下哪个事件会导致线程销毁?(D)

调用方法sleep()

调用方法wait()

start()方法的执行结束

run()方法的执行结束

在这里插入图片描述所以start方法只是让线程进入就绪状态而不是销毁

A. 调用sleep()方***让线程进入睡眠状态—睡眠指定的时间后再次执行;
B. 调用wait()方***让线程进入等待状态 ----等待别的线程执行notify()或notifyAll()唤醒后继续执行;
C.调用start()方***让线程进入就绪状态—得到CPU时间就执行线程;
D.run()方法是线程的具体逻辑方法,执行完,线程就结束。

在这里插入图片描述 看API中红框里的这句话,start方***开启一个新的线程执行run方法,所以start方法执行完,不代表run方法执行完,线程也不一定销毁!
所以C错误~

10 下面哪个行为被打断不会导致InterruptedException:( E)?

Thread.join

Thread.sleep

Object.wait

CyclicBarrier.await

Thread.suspend
抛InterruptedException的代表方法有:

    java.lang.Object 类的 wait 方法

    java.lang.Thread 类的 sleep 方法

    java.lang.Thread 类的 join 方法

11下列关于Java并发的说法中正确的是(B)

CopyOnWriteArrayList适用于写多读少的并发场景

ReadWriteLock适用于读多写少的并发场景

ConcurrentHashMap的写操作不需要加锁,读操作需要加锁

只要在定义int类型的成员变量i的时候加上volatile关键字,那么多线程并发执行i++这样的操作的时候就是线程安全的了

A,CopyOnWriteArrayList适用于写少读多的并发场景
B,ReadWriteLock即为读写锁,他要求写与写之间互斥,读与写之间互斥,
读与读之间可以并发执行。在读多写少的情况下可以提高效率
C,ConcurrentHashMap是同步的HashMap,读写都加锁
D,volatile只保证多线程操作的可见性,不保证原子性

12 关于多线程和多进程,下面描述正确的是():AC

多进程里,子进程可获得父进程的所有堆和栈的数据;而线程会与同进程的其他线程共享数据,拥有自己的栈空间。

线程因为有自己的独立栈空间且共享数据,所有执行的开销相对较大,同时不利于资源管理和保护。

线程的通信速度更快,切换更快,因为他们在同一地址空间内。

一个线程可以属于多个进程。

A.子进程得到的是除了代码段是与父进程共享以外,其他所有的都是得到父进程的一个副本,子进程的所有资源都继承父进程,得到父进程资源的副本,子进程可获得父进程的所有堆和栈的数据,但二者并不共享地址空间。两个是单独的进程,继承了以后二者就没有什么关联了,子进程单独运行;进程的线程之间共享由进程获得的资源,但线程拥有属于自己的一小部分资源,就是栈空间,保存其运行状态和局部自动变量的
B.线程之间共享进程获得的数据资源,所以开销小,但不利于资源的管理和保护;而进程执行开销大,但是能够很好的进行资源管理和保护
C.线程的通信速度更快,切换更快,因为他们共享同一进程的地址空间。
D.一个进程可以有多个线程,线程是进程的一个实体,是CPU调度的基本单位

1、一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程(通常说的主线程)。
2、资源分配给进程,同一进程的所有线程共享该进程的所有资源。
3、线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
4、处理机分给线程,即真正在处理机上运行的是线程。
5、线程是指进程内的一个执行单元,也是进程内的可调度实体。

13 关于ThreadLocal类 以下说法正确的是 DE

ThreadLocal继承自Thread

ThreadLocal实现了Runnable接口

ThreadLocal重要作用在于多线程间的数据共享

ThreadLocal是采用哈希表的方式来为每个线程都提供一个变量的副本

ThreadLocal保证各个线程间数据安全,每个线程的数据不会被另外线程访问和破坏

ThreadLocal继承Object,相当于没继承任何特殊的。
ThreadLocal没有实现任何接口。
ThreadLocal并不是一个Thread,而是Thread的局部变量。

ThreadLocal不是使用在多线程之间共享数据,使变量在每个线程中都有独立拷贝,不会出现一个线程读取变量时而被另一个线程修改的现象。

Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。

JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序,ThreadLocal并不是一个Thread,而是Thread的局部变量

1、ThreadLocal的类声明:
public class ThreadLocal
可以看出ThreadLocal并没有继承自Thread,也没有实现Runnable接口。所以AB都不对。
2、ThreadLocal类为每一个线程都维护了自己独有的变量拷贝。每个线程都拥有了自己独立的一个变量。
所以ThreadLocal重要作用并不在于多线程间的数据共享,而是数据的独立,C选项错。
由于每个线程在访问该变量时,读取和修改的,都是自己独有的那一份变量拷贝,不会被其他线程访问,
变量被彻底封闭在每个访问的线程中。所以E对。
3、ThreadLocal中定义了一个哈希表用于为每个线程都提供一个变量的副本:
static class ThreadLocalMap {

    static class Entry extends WeakReference<ThreadLocal> {
        /** The value associated with this ThreadLocal. */
        Object value;

        Entry(ThreadLocal k, Object v) {
            super(k);
            value = v;
        }
    }

    /**
     * The table, resized as necessary.
     * table.length MUST always be a power of two.
     */
    private Entry[] table;

}
所以D对。
14 有关线程的哪些叙述是对的(BCD)

一旦一个线程被创建,它就立即开始运行。

使用start()方法可以使一个线程成为可运行的,但是它不一定立即开始运行。

当一个线程因为抢先机制而停止运行,它可能被放在可运行队列的前面。

一个线程可能因为不同的原因停止并进入就绪状态。

一个新创建的线程并不是自动的开始运行的,必须调用它的start()方法使之将线程放入可运行态(runnable state),这只是意味着该线程可被JVM的线程调度程序调度而不是意味着它可以立即运行。
线程的调度是抢先式的,而不是分时间片式的。
具有比当前运行线程高优先级的线程可以使当前线程停止运行而进入就绪状态。
不同优先级的线程间是抢先式的,而同级线程间是轮换式的。
一个线程停止运行可以是因为不同原因,可能是因为更高优先级线程的抢占,也可能是因为调用sleep()方法。
而即使是因为抢先而停止也不一定就进入可运行队列的前面,因为同级线程是轮换式的,它的运行可能就是因为轮换,而它因抢占而停止后只能在轮换队列中排队而不能排在前面。

猜你喜欢

转载自blog.csdn.net/ningmengshuxiawo/article/details/110294594