1、创建线程有哪几种方式?

  创建线程有3种方式,分别是继承Thread类、实现Runnable类、实现Callable类。

  继承Thread类的步骤:

    1. 定义Thread类的子类,并重写run()方法,该run方法将作为线程执行体;

    2. 创建线程对象,即Thread子类的实例;

    3. 调用线程对象的start()方法启动该线程。

  实现Runnable类的步骤:

    1. 定义Runnable接口的实现类,并实现该接口的run()方法,该方法将作为线程执行体;

    2. 创建Runnable实现类的实例,并将其作为Thread的target来创建Thread对象,Thread作为线程对象;

    3. 调用线程对象的start()方法启动该线程。

  实现Callable类的步骤:

    1. 定义Callable接口的实现类,并实现该接口的call()方法,该方法将作为线程执行体,且该call()方法有返回值,再创建Callable实现类类的实例;

    2. 使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()的返回值;

    3. 使用FutureTask对象作为Thread对象的target创建并启动新线程;

    4. 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。 

扩展阅读
  通过继承Thread类、实现Runnable接口、实现Callable接口都可以实现多线程,不过实现Runnable接口与实现Callable接口的方式基本相同,只是Callable接口里定义的方法有返回值,可以声明抛出异常而已。因此可以将实现Runnable接口和实现Callable接口归为一种方式。
采用实现Runnable、Callable接口的方式创建多线程的优缺点:
  • 线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。
  • 在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
  • 劣势是,编程稍稍复杂,如果需要访问当前线程,则必须使用Thread.currentThread()方法。
采用继承Thread类的方式创建多线程的优缺点:
  • 劣势是,因为线程类已经继承了Thread类,所以不能再继承其他父类。
  • 优势是,编写简单,如果需要访问当前线程,则无须使用Thread.currentThread()方法,直接使用this即可获得当前线程。
鉴于上面分析,因此一般推荐采用实现Runnable接口、Callable接口的方式来创建多线程。

2、Thread类的常用方法

  Thread类常用构造方法:
  • Thread()
  • Thread(String name)
  • Thread(Runnable target)
  • Thread(Runnable target, String name)
  其中,参数 name为线程名,参数 target为包含线程体的目标对象。
  
  Thread类常用静态方法:
  • currentThread():返回当前正在执行的线程;
  • interrupted():返回当前执行的线程是否已经被中断;
  • sleep(long millis):使当前执行的线程睡眠多少毫秒数;
  • yield():使当前执行的线程自愿暂时放弃对处理器的使用权并允许其他线程执行;
  Thread类常用实例方法:
  • getId():返回该线程的id;
  • getName():返回该线程的名字;
  • getPriority():返回该线程的优先级;
  • interrupt():使该线程中断;
  • isInterrupted():返回该线程是否被中断;
  • isAlive():返回该线程是否处于活动状态;
  • isDaemon():返回该线程是否是守护线程;
  • setDaemon(boolean on):将该线程标记为守护线程或用户线程,如果不标记默认是非守护线程;
  • setName(String name):设置该线程的名字;
  • setPriority(int newPriority):改变该线程的优先级;
  • join():等待该线程终止;
  • join(long millis):等待该线程终止,至多等待多少毫秒数。

3、run()和start()有什么区别

  run()方法被称为线程执行体,它的方法体代表了线程需要完成的任务,而start()方法用来启动线程。

  调用start()方法启动线程时,系统会把该run()方法当成线程执行体来处理。但如果直接调用线程对象的run()方法,则run()方法立即就会被执行,而且在run()方法返回之前其他线程无法并发执行。也就是说,如果直接调用线程对象的run()方法,系统把线程对象当成一个普通对象,而run()方法也是一个普通方法,而不是线程执行体。
 
4、线程是否可以重复启动,会有什么后果
  只能对处于新建状态的线程调用start()方法,否则将引发IllegalThreadStateException异常。
  当new一个线程之后,该线程处于新建状态,与其他的Java对象一样,仅仅由Java虚拟机为其分配了内存,并初始化其成员变量。当线程对象调用了star()方法后,该线程处于就绪状态,Java虚拟机为其创建方法调用栈和程序计数器,处于这个状态下的线程并没有开始运行,只是表示可以运行了。至于何时运行,取决于JVM里的线程调度器的调度。
 
5、介绍下线程的生命周期
  
 
6、如何实现线程同步
  1. 同步方法
  即由synchronized关键字修饰的方法,由于每一个对象都有一个内置锁,当用此关键字方法
时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。synchronized关键字也可以修饰静态方法,此时此时调用带静态方法,将会锁住整个类。
  2. 同步代码块
  即有synchronzed关键字修饰的语句块,被该关键字修饰的代码块会自动被扣上内置锁,从而实现同步。此外,同步是一种高开销的操作,因此应该尽量减少同步内容,只需同步关键代码即可。
  3. ReentrantLock
  Java 5新增了一个java.util.concurrent包来支持同步,其中ReentrantLock类是可重入、互斥、实现了Lock接口的锁,与synchronzed有相同的基本行为和语义,并扩展了能力。ReentantLock还有一个创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不建议使用
  4、volatile
  volatile关键字为域变量的访问提供了一种免锁机制,使用Volatile修饰域相当于告诉虚拟机该域可能被其他线程更新,因此每次使用该域就要重新计算,而不是用寄存器中的值。需要注意的是,volatile不会提供任何原子操作,它也不会用来修饰final类型的变量
  5、原子变量
  在java的util.concurrent.atomic包中提供了创建了原子类型变量的工具类,使用该类可以简化线程同步。例如AtomicInteger 表可以用原子方式更新int的值,可用在应用程序中(如以原子方式增加的计数器),但不能用于替换Integer。可扩展Number,允许那些处理机遇数字类的工具和实用工具进行统一访问。
7、Java多线程之间的通讯方式
  1. wait()、notify()、notifyAll()
  2. await()、signal()、signalAll()
  3. BlockingQueue
8、说一说Java同步机制中的wait和notify
  当线程之间采用synchronized来保证线程安全,可以使用wait()、notify()、notifyAll()都是用来实现线程通讯。
  这三个方法都不是Thread类中声明的方法,而是Object类中声明的方法。原因是,每个对象都拥有锁,让当前进程等待某个对象的锁,应当通过这个对象来操作。并且当前线程可能同时等待多个线程的锁,若通过线程来操作,会更复杂。
  另外,这三个方法都是本地方法,被final修饰没无法被重写。
9、sleep()和wait()的区别
  sleep()是Thread类中的静态方法,而wait()是Object类中的成员方法;
  sleep()可以在任何地方使用,而wait()只能在同步方法或同步代码块中使用;
  sleep()不会释放锁,而wait()会释放锁,并需要通过notify()/notifyAll()重新获取锁。
10、notify()、notifyAll()的区别
  notify():用于唤醒一个正在等待对象锁的线程,使其进入就绪队列,以便当前线程释放锁后竞争锁,进而得到CPU的执行。
  notifyAll():用于唤醒所有正在等待对象锁的线程,使其进入就绪队列,以便当前线程释放锁后竞争锁,进而得到CPU的执行。

JAVA面经-基础篇-线程的更多相关文章

  1. Java多线程系列--“基础篇”05之 线程等待与唤醒

    概要 本章,会对线程等待/唤醒方法进行介绍.涉及到的内容包括:1. wait(), notify(), notifyAll()等方法介绍2. wait()和notify()3. wait(long t ...

  2. Java多线程系列--“基础篇”06之 线程让步

    概要 本章,会对Thread中的线程让步方法yield()进行介绍.涉及到的内容包括:1. yield()介绍2. yield()示例3. yield() 与 wait()的比较 转载请注明出处:ht ...

  3. Java多线程系列--“基础篇”07之 线程休眠

    概要 本章,会对Thread中sleep()方法进行介绍.涉及到的内容包括:1. sleep()介绍2. sleep()示例3. sleep() 与 wait()的比较 转载请注明出处:http:// ...

  4. Java多线程系列--“基础篇”09之 interrupt()和线程终止方式

    概要 本章,会对线程的interrupt()中断和终止方式进行介绍.涉及到的内容包括:1. interrupt()说明2. 终止线程的方式2.1 终止处于“阻塞状态”的线程2.2 终止处于“运行状态” ...

  5. Java多线程系列--“基础篇”10之 线程优先级和守护线程

    概要 本章,会对守护线程和线程优先级进行介绍.涉及到的内容包括:1. 线程优先级的介绍2. 线程优先级的示例3. 守护线程的示例 转载请注明出处:http://www.cnblogs.com/skyw ...

  6. Java多线程系列--“基础篇”11之 生产消费者问题

    概要 本章,会对“生产/消费者问题”进行讨论.涉及到的内容包括:1. 生产/消费者模型2. 生产/消费者实现 转载请注明出处:http://www.cnblogs.com/skywang12345/p ...

  7. Java多线程系列--“基础篇”04之 synchronized关键字

    概要 本章,会对synchronized关键字进行介绍.涉及到的内容包括:1. synchronized原理2. synchronized基本规则3. synchronized方法 和 synchro ...

  8. Java多线程系列--“基础篇”02之 常用的实现多线程的两种方式

    概要 本章,我们学习“常用的实现多线程的2种方式”:Thread 和 Runnable.之所以说是常用的,是因为通过还可以通过java.util.concurrent包中的线程池来实现多线程.关于线程 ...

  9. Java多线程系列--“基础篇”03之 Thread中start()和run()的区别

    概要 Thread类包含start()和run()方法,它们的区别是什么?本章将对此作出解答.本章内容包括:start() 和 run()的区别说明start() 和 run()的区别示例start( ...

  10. Java多线程系列--“基础篇”08之 join()

    概要 本章,会对Thread中join()方法进行介绍.涉及到的内容包括:1. join()介绍2. join()源码分析(基于JDK1.7.0_40)3. join()示例 转载请注明出处:http ...

随机推荐

  1. Linux LVM分区相关知识

    Linux分区有多种方式,一种是LVM格式的比较方便,另一种是标准分区扩容比较麻烦,麻烦的事情那么出错的概率也就越大,所以建议生产环境上分区都使用LVM格式硬盘分区. 一.    什么叫LVM?  L ...

  2. WPF绑定(4)

    什么是绑定(Binding)? 在winform中, 我们常常会用到各种类型的赋值, 例如: button1.Text="Hello"; label.Text="Hell ...

  3. 【godis】skiplist

    skiplist 前言:在看代码时看到 ZSKIPLIST_MAXLEVEL = 32,当时并不了解 ZSKIPLIST_P 的作用,想着用 2 分法不应该层数是 64 吗?书上和他人的代码都是基于 ...

  4. fix: because the volume group on the selected device also consist of physical volumes on other devices

    because the volume group on the selected device also consist of physical volumes on other devices 目标 ...

  5. 删除File Explorer、This PC、Folders

    win+R,输入regedit,打开Registry Editor 定位:Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentV ...

  6. video.js 苹果手机设置了currentTime却还是从头播放?

    最近在项目(方案大赛)中需要保存学习进度,用户再打开页面时会从上次的视频进度继续观看.我们使用了video.js,在PC浏览器和安卓手机上均可以跳转,但是苹果手机很顽固的从头开始了呢-- 后来我们在 ...

  7. HttpWebResponse 四种accept-encoding解析(gzip, deflate, br,identity)

    HttpWebResponse 四种accept-encoding解析(gzip, deflate, br,identity[默认])            var hwrs = (HttpWebRe ...

  8. ctfshow web入门41

    这个题过滤了$.+.-.^.~使得异或自增和取反构造字符都无法使用,同时甚至过滤了字母和数字. 但是特意留了个或运算符|. 由此我们可以尝试从ascii为0-255的字符中,找到用或运算能得到我们可用 ...

  9. mybatis核心配置文件—设置别名typeAliases

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC & ...

  10. Linux如何设置用户登录超时(/etc/profile)

    1. 针对所有用户 # vi /etc/profile ... export TMOUT=900 # 设置闲置时间为15分钟,单位为秒;如果没有此行则直接添加进去 ... vi /etc/profil ...