线程问题总结


什么是线程?

线程是指程序在执行过程中,能够执行程序代码的一个执行单元,在Java语言中,线程有四种状态:运行,就绪,挂起,结束。


线程与进程的区别?

进程是一段正在运行的程序,而线程有时也被称为轻量级进程,它是进程的执行单元,一个进程可以拥有多个线程,各个线程之间共享程序的内存空间,但是,各个线程拥有自己的栈空间。


为什么使用多线程?

(1)、使用多线程可以减少程序的响应时间。单线程如果遇到等待或阻塞,将会导致程序不响应鼠标键盘等操作,使用多线程可以解决此问题,增强程序的交互性。

(2)、与进程相比,线程的创建和切换开销更小,因为线程共享代码段、数据段等内存空间。

(3)、多核CPU,多核计算机本身就具有执行多线程的能力,如果使用单个线程,将无法重复利用计算资源,造成资源的巨大浪费。

(4)、多线程可以简化程序的结构,使程序便于维护,一个非常复杂的进程可以分为多个线程执行。


多线程出现的原因:

为了解决负载均衡问题,充分利用CPU资源.为了提高CPU的使用率,采用多线程的方式去同时完成几件事情而不互相干扰.为了处理大量的IO操作时或处理的情况需要花费大量的时间等等,比如:读写文件,视频图像的采集,处理,显示,保存等

多线程的好处:

1.使用线程可以把占据时间长的程序中的任务放到后台去处理

2.用户界面更加吸引人,这样比如用户点击了一个按钮去触发某件事件的处理,可以弹出一个进度条来显示处理的进度

3.程序的运行效率可能会提高

4.在一些等待的任务实现上如用户输入,文件读取和网络收发数据等,线程就比较有用了.

多线程的缺点:

1.如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换.

2.更多的线程需要更多的内存空间

3.线程中止需要考虑对程序运行的影响.

4.通常块模型数据是在多个线程间共享的,需要防止线程死锁情况的发生


顺序执行流:单个线程的程序只有一个顺序执行流,多线程的程序则可以包含多个顺序执行流,多个顺序执行流之间互不干扰。

一个任务通常就是一个程序,每个运行中的程序就是一个进程。当程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程。

进程和线程:运行中的任务,即当一个程序进入内存时,每个运行中的程序就是一个进程。当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程。线程是进程的组成部分,一个进程可包含多个线程,一个线程必须有一个你进程。线程拥有自己的堆栈,程序计数器,局部变量,但不拥有系统资源。它与父进程的其他线程共享此进程所拥有的全部资源。线程共享的环境包括:进程代码块,进程的公有数据等。利用共享的数据,线程很容易实现相互之间的通信。

进程三个特征:独立性,动态性,并发性。

并发性与并行性:并发性,同一时刻,有多条指令在多个处理器上执行。并发性,同一时刻只有一条指令执行,但多个进程指令被快速轮换执行。


多线程编程的优势

1、进程之间不能共享内存,线程之间容易共享内存。

2、系统创建进程时需要为该进程重新分配系统资源,但创建线程时则代价小得多,因此通过多线程来实现多任务并发比多进程的效率高。

3、Java语言内置了多线程功能支持。


实际应用

浏览器能同时下载多个图片;Web服务器响应多个用户响应;Java虚拟机提供了超级进程来进行垃圾回收。。。


线程的创建和启动

1、继承Thread类创建线程类

Java程序运行后,程序至少创建一个主线程,主线程的线程执行休是由main()确定的——main方法的方法体代表主线程的线程执行体。使用Thread类方法创建线程时,多个线程之间无法共享线程类的实例变量。

2、实现Runnable接口创建线程类

Runnable对象仅作为Thread对象的target,而实际的线程对象依然是Thread实例,只是该Thread线程负责执行target的run()方法。采用Runable接口的方式创建的多个线程可以共享线程类的实例属性。因为在这种方式下,程序所创建的Runable对象只是线程的target,而多个线程可以共享一个target。所以多个线程可以共享一个线程类的实例属性。

3、使用Callable接口和Future创建线程

Callable接口提供了一个call()方法可以作为线程执行休,call()方法,可有返回值,可声明抛出异常。Callable对象不能直接作为Thread的target。

Future接口来代表Callable接口里call()的返回值。FutureTask为Future的一个实现类,并实现了Runnable接口——可以作为Thread的target。

三、线程的生命周期

线程的五个状态:新建New,就绪Runnable,运行Running,阻塞Blocked,死亡Dead。

新建:用new关键字创建一个线程时

就绪:调用start()方法后,Java虚拟机会为其创建方法调用栈和程序计数器,何时执行,取决于JVM里线程调试器的调度。相当于”等待执行“。如果希望调用子线程的start()方法后子线程立即开始执行,程序可以使用Thread.sleep(1)方法让当前运行的线程(主线程)睡眠一毫秒,则处于就绪状态的子线程将立即开始执行。

运行:处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态。

阻塞:线程运行后,不可能一直处于运行状态,除非它线程执行体足够短,瞬间执行体结束了。线程在运行过程中需要被中断(抢占式调试策略,协作工调试策略),目前的是使其他线程获得执行的机会。线程调试的细节取决于底层平台所采用的策略。

进入阻塞状态的情况以及解除阻塞的情况,以及状态转移图如下:

死亡:run(),call()方法执行完成后,线程抛出一个未捕获的异常,stop()方法。isAlive()方法,当线程处于,就绪,运行,阻塞状态时,返回true;新建,死亡时,返回false。


Executors类是什么

Executors为Executor,ExecutorService,ScheduledExecutorService,ThreadFactory和Callable类提供了一些工具方法。

Executors可以用于方便的创建线程池。


什么是FutureTask?

FutureTask是Future的一个基础实现,我们可以将它同Executors使用处理异步任务。通常我们不需要使用FutureTask类,单当我们打算重写Future接口的一些方法并保持原来基础的实现是,它就变得非常有用。我们可以仅仅继承于它并重写我们需要的方法。


用户线程和守护线程有什么区别?

当我们在Java程序中创建一个线程,它就被称为用户线程。一个守护线程是在后台执行并且不会阻止JVM终止的线程。当没有用户线程在运行的时候,JVM关闭程序并且退出。一个守护线程创建的子线程依然是守护线程。


线程生命周期?

新建、就绪、运行(活动)、阻塞和死亡。

创建并运行线程:

① 新建状态(New Thread):在Java语言中使用new 操作符创建一个线程后,该线程仅仅是一个空对象,它具备类线程的一些特征,但此时系统没有为其分配资源,这时的线程处于创建状态。Thread  t1=new Thread();

线程处于创建状态时,可通过Thread类的方法来设置各种属性,如线程的优先级(setPriority)、线程名(setName)和线程的类型(setDaemon)等。

② 就绪状态(Runnable):使用start()方法启动一个线程后,系统为该线程分配了除CPU外的所需资源,即正在等待被分配给CPU时间片,使该线程处于就绪状态,也就是说此时线程正在就绪队列中排队等候得到CPU资源。此外,如果某个线程执行了yield()方法,那么该线程会被暂时剥夺CPU资源,重新进入就绪状态。例如:t1.start();

③ 运行状态(Running):Java运行系统通过调度选中一个处于就绪状态的线程,使其占有CPU并转为运行状态。此时,系统真正执行线程的run()方法,即线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。

a)     可以通过Thread类的isAlive方法来判断线程是否处于就绪/运行状态:当线程处于就绪/运行状态时,isAlive返回true,当isAlive返回false时,可能线程处于阻塞状态,也可能处于停止状态。

④ 阻塞和唤醒线程

阻塞状态(Blocked):一个正在运行的线程因某些原因不能继续运行时,就进入阻塞 状态。这些原因包括:

a)          当执行了某个线程对象的sleep()等阻塞类型的方法时,该线程对象会被置入一个阻塞集内,等待超时而自动苏醒。

b)          当多个线程试图进入某个同步区域时,没能进入该同步区域的线程会被置入锁定集,直到获得该同步区域的锁,进入就绪状态。

c)          当线程执行了某个对象的wait()方法时,线程会被置入该对象的等待集中,直到执行了该对象的notify()方法wait()/notify()方法的执行要求线程首先获得该对象的锁。

⑤ 死亡状态(Dead):线程在run()方法执行结束后进入死亡状态。此外,如果线程执行了interrupt()或stop()方法,那么它也会以异常退出的方式进入死亡状态。

终止线程的三种方法

① 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止,推荐使用。

② 使用stop方法强制终止线程(这个方法不推荐使用,因为stop和suppend、resume一样,也可能发生不可预料的结果)。

③ 使用interrupt方法中断线程。

常用方法

void run()   创建该类的子类时必须实现的方法

void start() 开启线程的方法

static void sleep(long t) 释放CPU的执行权,不释放锁

static void sleep(long millis,int nanos)

final void wait()释放CPU的执行权,释放锁

final void notify()

static void yied()可以对当前线程进行临时暂停(让线程将资源释放出来)


你对线程优先级的理解是什么?

每一个线程都是有优先级的,一般来说,高优先级的线程在运行时会具有优先权,但这依赖于线程调度的实现,这个实现是和操作系统相关的(OS dependent)。我们可以定义线程的优先级,但是这并不能保证高优先级的线程会在低优先级的线程前执行。线程优先级是一个int变量(从1-10),1代表最低优先级,10代表最高优先级。


线程调度器(Thread Scheduler)和时间分片(Time Slicing)

线程调度器是一个操作系统服务,它负责为Runnable状态的线程分配CPU时间。一旦我们创建一个线程并启动它,它的执行便依赖于线程调度器的实现。时间分片是指将可用的CPU时间分配给可用的Runnable线程的过程。分配CPU时间可以基于线程优先级或者线程等待的时间。线程调度并不受到Java虚拟机控制,所以由应用程序来控制它是更好的选择(也就是说不要让你的程序依赖于线程的优先级)。


上下文切换

先来解释一下什么是上下文切换(context switch)。在多任务处理系统中,作业数通常大于CPU数。为了让用户觉得这些任务在同时进行,CPU给每个任务分配一定时间,把当前任务状态保存下来,当前运行任务转为就绪(或者挂起、删除)状态,另一个被选定的就绪任务成为当前任务。之后CPU可以回过头再处理之前被挂起任务。上下文切换就是这样一个过程,它允许CPU记录并恢复各种正在运行程序的状态,使它能够完成切换操作。在这个过程中,CPU会停止处理当前运行的程序,并保存当前程序运行的具体位置以便之后继续运行。


为什么线程通信的方法wait(), notify()和notifyAll()被定义在Object类里?

Java的每个对象中都有一个锁(monitor,也可以成为监视器) 并且wait(),notify()等方法用于等待对象的锁或者通知其他线程对象的监视器可用。在Java的线程中并没有可供任何对象使用的锁和同步器。这就是为什么这些方法是Object类的一部分,这样Java的每一个类都有用于线程间通信的基本方法


为什么Thread类的sleep()和yield()方法是静态的?

Thread类的sleep()和yield()方法将在当前正在执行的线程上运行。所以在其他处于等待状态的线程上调用这些方法是没有意义的。这就是为什么这些方法是静态的。它们可以在当前正在执行的线程中工作,并避免程序员错误的认为可以在其他非运行线程调用这些方法。


如何确保线程安全?

在Java中可以有很多方法来保证线程安全——同步,使用原子类(atomic concurrent classes),实现并发锁,使用volatile关键字,使用不变类和线程安全类。


volatile关键字在Java中有什么作用?

当我们使用volatile关键字去修饰变量的时候,所以线程都会直接读取该变量并且不缓存它。这就确保了线程读取到的变量是同内存中是一致的。


同步方法和同步块,哪个是更好的选择?

同步块是更好的选择,因为它不会锁住整个对象(当然你也可以让它锁住整个对象)。同步方法会锁住整个对象,哪怕这个类中有多个不相关联的同步块,这通常会导致他们停止执行并需要等待获得这个对象上的锁。


如何创建守护线程?

使用Thread类的setDaemon(true)方法可以将线程设置为守护线程,需要注意的是,需要在调用start()方法前调用这个方法,否则会抛出IllegalThreadStateException异常。


并发,同步,异步?

并发:在单核和多核都可存在,就是同一时间有多个可以执行的进程但是在单核中同一时刻只有一个进程获得CPU,虽然宏观上你认为多个进程都在进行。多个用户争夺同一个资源(这个资源可以是服务器上的日志,可以是执行某一此sql操作,可以使ftp服务器上的某个文件等,又或者是程序中的某一个全局变量,因此我们可以称这种资源为:全局资源);

并行:是指同一时间多个进程在微观上都在真正的执行,这就只有在多核的情况下了。

(如果一台计算机有n个处理器,那么就有n个线程真正同时运行。单CPU计算机是伪并行,按照某种调度算法,多个轮流运行)

其中两种并发关系分别是同步和互斥。

互斥:进程间相互排斥的使用临界资源的现象,就叫互斥。

解释:并发是在多个用户请求同一个资源的时候,或者是程序本身多线程请求同一个资源的时候造成的。

比如:一个财务系统,两个人同时对总钱数进行操作,一个加10块一个减100块,注意这两个操作是同时进行的,那系统就不知道是加还是减了,这是并发问题。或者,多个线程同时请求同一个资源,必然导致此资源的数据不安全,A线程修改了B线程的处理的数据,而B线程又修改了A线程处理的数理(线程安全)。

异步:A线程要请求某个资源,但是此资源正在被B线程使用中,因为没有同步机制存在,A线程

仍然请求的到这个资源,A线程无需等待。

同步:A线程要请求某个资源,但是此资源正在被B线程使用中,因为同步机制存在,A线程请求

不到,怎么办,A线程只能等待下去。

同步与异步:显然,同步最安全,最保险的。而异步不安全,容易导致死锁,这样一个线程死掉就会导致整个

进程崩溃,但没有同步机制的存在,性能会有所提升。所以对于同步与异步必须有所取舍。



































http://www.cnblogs.com/gongxing/p/4663066.html

http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-answers/

http://www.cnblogs.com/wzy330782/p/5456923.html

http://blog.csdn.net/bieleyang/article/details/76648599

http://blog.csdn.net/lee_sire/article/details/50371962

http://blog.csdn.net/antony9118/article/details/51475034


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • 下面是我自己收集整理的Java线程相关的面试题,可以用它来好好准备面试。 参考文档:-《Java核心技术 卷一》-...
    阿呆变Geek阅读 14,738评论 14 507
  • 又来到了一个老生常谈的问题,应用层软件开发的程序员要不要了解和深入学习操作系统呢? 今天就这个问题开始,来谈谈操...
    tangsl阅读 4,088评论 0 23
  • 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题。Java语言一个重要的特点就是内置了对并发的支持,让...
    尧淳阅读 1,588评论 0 25
  • 有点疼 拥抱了分离, 感觉有点疼。 那向着风飘散的, 那如雪花的感情, 那像轻烟般消散的, 都在骨血里沸腾。 对不...
    感悟多的干物女阅读 179评论 0 2
  • 你是所有的音乐倾倒, 最后剩下来的那一章。 你是所有的笔墨饮尽, 最后窖藏蓬莱的半壶。 你是桃源尽头的厚雪。 最后...
    唐诗远阅读 568评论 12 24