JAVA多线程

来源:互联网 发布:python spark视频教程 编辑:程序博客网 时间:2024/06/03 11:49

1.线程的实现方式

 1)继承Thread类

 如果直接调用对象的run方法,这时底层资源并没有完成资源的创建和执行,仅是简单的对象调用。

 而且使用run方法,是不可以并行,不可以交叉执行的,调用run方法执行的是main这个线程。

 线程的并行,交叉执行,有随机性,哪条线程先执行没有定性,由CPU决定的。

 如果想开启线程,需要去调用thread类中的另一个方法,start来完成;

 此start做了两件事情:开启线程 ; 调用线程的run方法。


 2)实现runable接口

 子类覆盖接口Runable的run方法

 通过thread类创建线程,并将实现了Runable接口的子类对象作为参数传递到thread类的构造函数

 thread类对象调用start方法开启线程


2.两者的优缺点

 避免了点继承的局限性,一个类可以继承多个接口

 适合于资源共享

 student继承person类,student想有runable方法,但person不需要有这个方法


3.线程的生命周期

 线程通过new方法创建,调用start()方法,线程进入就绪状态,等待系统的调度(时间片轮转调度)。当系统调度,调用run()方法,进入运行状态。正常run()方法执行结束或者stop()方法退出,进程进入死亡状态。
 处于运行状态的线程若遇到sleep()方法,则线程进入阻塞睡眠状态,不会让出资源锁,sleep()方法结束,线程转为就绪状态,等待系统重新调度。
 处于运行状态的线程遇到wait() 方法(object的方法),线程处于阻塞等待状态,需要notify()/notifyALL()来唤醒线程,唤醒后的线程处于锁定状态,获取了“同步锁”,之后,线程才转为就绪状态。

4.同步代码块

 多线程在执行的时候,可能会存在安全隐患,为了解决这个问题,引入了同步机制

 syschronized

 同步代码块

 syschronized(obj){

 }

 但是,使用同步,每次都要进行标志位的判断,效率低

 同步的前提:

 1)同步需要两个或两个以上的线程

 2)多个线程使用的是同一个锁


5.守护线程

 QQ空间里背景音乐,你打开空间就开始放音乐,你把浏览器关了,它就跟着结束了,也不管音乐是不是放完了

 setDaemon  将线程标记为守护线程或用户线程

 isDaemon  测试该线程是否为守护线程


6.yield

 暂停当前执行的线程,并执行其他线程,进入到就绪状态,并不是阻塞。停掉之后还是有机会去抢这个资源的。


7.线程的优先级

 setPriority  更改线程的优先级

 getPriority  返回线程的优先级


8.线程池

 Executor.newCacheThreadPool()  缓存功能的线程池

 Executor.newFixedThreadPool()  可重复,具有固定线程数的线程池

 Executor.newSingleThreadPool()  单线程的线程池

 Executor.newScheduledThreadPool() 

 Executor.newSigleThreadScheduledExecutor()()  创建只有一个线程的线程池,可以指定延迟后执行线程任务


9.线程安全

 代码所在进程中有多个线程同时运行,而这些线程可能会同时运行这段代码,每次运行的结果和单线程运行的结果是一样的


10.一个线程运行时发生异常会怎样

 如果异常没有被捕获,该线程就会停止执行


11.如何在两个线程间共享数据

 可以通过共享对象,或者使用阻塞队列这样的结构


12.notify 和 notifyall 的区别

  notify 不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有用武之地

  notifyall 唤醒所有线程并允许他们争夺锁确保了至少有一个线程才能继续运行


13.堆和栈的区别

  每个线程都有自己的栈内存,用于存变量,方法,对其他线程是不可见的;

  堆内存,线程共用的区域


14.什么是线程池?为什么要使用线程池?

  创建线程需要花费资源和时间,任务来了才创建线程,会导致响应时间长,而且进程能创建的线程数有限。

  为了避免这些问题,程序启动的时候,就创建若干线程来响应处理,就被称之为线程池。