目录:

进程和线程

为什么使用多线程?

多线程的创建方式

Runnable与Thread两种方式比较

start()与run()方法

线程的生命周期/状态转换

常用方法使用与解读

线程的优先级

守护线程

1、进程和线程

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。

一个程序就是一个进程,而一个程序中的多个任务则被称为线程。

进程是表示资源分配的基本单位,线程是进程中执行运算的最小单位,亦是调度运行的基本单位。

2、为什么要使用多线程?

提升效率,提升性能;发挥多核CPU的优势。

防止阻塞:从程序运行效率的角度来看,单核CPU不但不会发挥出多线程的优势,反而会因为在单核CPU上运行多线程导致线程上下文的切换,而降低程序整体的效率。但是单核CPU我们还是要应用多线程,就是为了防止阻塞。试想,如果单核CPU使用单线程,那么只要这个线程阻塞了,比方说远程读取某个数据吧,对端迟迟未返回又没有设置超时时间,那么你的整个程序在数据返回回来之前就停止运行了。多线程可以防止这个问题,多条线程同时运行,哪怕一条线程的代码执行读取数据阻塞,也不会影响其它任务的执行。

3、多线程的创建方式[细分为5种]

继承Thread类,重写run方法。new一个实例。

实现Runnable接口,重写run方法。作为参数传入Thread thread = new Thread(参数);来创建。

匿名内部类的方式(与实现Runnable接口一样,只是形式不同 )

通过并发包中Callable、Callback来创建

通过线程池来创建线程

4、Runnable与Thread两种方式比较

继承Thread不必多说,继承后重写run方法。new一个实例调用start()方法就可以了。

两者非要比较的话,使用Runnable较好,因为实现接口的方式比继承类的方式更灵活,也能减少程序之间的耦合度,面向接口编程也是设计模式6大原则的核心。

这里重点看下实现Runnable接口创建线程,实现Runnable接口实际上还是需要Thread类来创建线程,我们来看下Thread的构造方法API:

另外需要说明的是Thread.java类也实现了Runnable接口,如下图:

那也就意味着Thread的构造函数不仅可以传入Runnable接口的对象还可以传入一个Thread类的对象,这样就可以将一个Thread类的run()方法交由其他线程来调用。

5、start()与run()方法

只有调用了start()方法,才会表现出多线程的特性,不同线程的run()方法里面的代码交替执行。如果只是调用run()方法,那么代码还是同步执行的,必须等待一个线程的run()方法里面的代码全部执行完毕之后,另外一个线程才可以执行其run()方法里面的代码。

6、线程的生命周期/状态转换

生命周期的五种状态【简单版文字描述】:

新建(new Thread)当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。

例如:Thread t1=new Thread();

就绪(runnable)线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。例如:t1.start();

运行(running)线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。

死亡(dead)

当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。

自然终止:正常运行run()方法后终止

异常终止:调用stop()方法让一个线程终止运行,这里说明下stop()方法虽然可以停止线程,但这个方法线程不安全,在新版本的java中已经被废弃。

堵塞(blocked)

由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。

正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。

正在等待:调用wait()方法。(调用notify()方法回到就绪状态)

被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)废弃

更全的线程状态转换图如下:

7、常用方法使用与解读

start():使线程进入“就绪”(可运行)状态,通知jvm开启新线程来执行run方法。如果多次调用了start()方法,则会出现Exception in thread "main" java.lang.IllegalThreadStateException因为start会修改当前线程的状态变量,只有状态变量是初始值时才能start。

线程中断相关:

stop()【废弃】:停止一个线程,可以使用Thread.stop()方法,但是他是不安全的,而且已经被废弃了呢。调用的时候还会抛出一个java.lang.ThreadDeath异常 ,但是通常情况下,此异常不需要显示的捕捉。废弃原因:因为强制让线程停止则有可能使一些请理性的工作得不到完成。另外情况就是对锁定的对象进行了“解锁”,导致 数据得不到同步的处理,出现数据不一致的问题。

interrupt():大多数停止一个线程的操作是使用Thread.interrupt()方法,尽管名义为“中止,停止”但这个方法不会终止一个正在运行的线程,只是打了一个标记,还需要加入一个判断才可以完成线程的停止。Thread.java中提供了两个方法:

this.interrupted():测试当前线程是否已经中断。public static boolean interrupted()

this.isInterrupted():测试线程是否已经中断。public boolean isInterrupted()

具体终止线程操作(来源网络):https://www.cnblogs.com/jenkov/p/juc_interrupt.html

其中的return停止线程可以的,但是还是建议使用“抛异常”的方法来实现线程的停止,因为在catch块中还可以将异常上抛,使线程停止的事件得以传播。

另外这两个方法的区别:

interrupted()无论怎么都是指正在运行的线程。而isInterrupted()就是表示指定的线程咯。

interrupted()会清除标记,什么意思呢?就是调用interrupt()给当前线程打一个中断标记,第一次用interrupted()会返回true但是 如果不处理,之后的调用都会返回false因为它把中断标记给清了。

暂停线程相关:

suspend()与resume()【废弃】:一个暂停线程,一个恢复线程到运行状态。suspend()会暂停线程,假如当前线程为关键数据结构加锁 这时被挂起那么锁将无法释放对其他线程来说造成死锁。同时也会因为线程的暂停出现数据不同步的现象。

currentThread():该方法返回代码段正在被那个线程调用的信息。

isAlive():判断当前线程是否处于活动的状态。活动状态是指线程已经启动尚未终止的状态。线程处于正在运行或准备开始运行的状态,就认为线程是“存活”的。

sleep():在指定毫秒内让当前正在执行的线程休眠。这个“正在执行的线程”是指this.currentThread()返回的线程。

getId():取得线程的唯一标识。这个是自动分配的,且是唯一的。

yield():放弃当前的CUP资源,将它让给其他的任务去占用CPU执行时间。但是放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片。

8、线程的优先级

线程可以划分优先级,CPU优先执行优先级较高的线程对象中的任务。

设置线程的优先级使用setPriority()方法,该方法的源码如下:

/**

* Changes the priority of this thread.

*

* First the checkAccess method of this thread is called

* with no arguments. This may result in throwing a

* SecurityException.

*

* Otherwise, the priority of this thread is set to the smaller of

* the specified newPriority and the maximum permitted

* priority of the thread's thread group.

*

* @param newPriority priority to set this thread to

* @exception IllegalArgumentException If the priority is not in the

* range MIN_PRIORITY to

* MAX_PRIORITY.

* @exception SecurityException if the current thread cannot modify

* this thread.

* @see #getPriority

* @see #checkAccess()

* @see #getThreadGroup()

* @see #MAX_PRIORITY

* @see #MIN_PRIORITY

* @see ThreadGroup#getMaxPriority()

*/

public final void setPriority(int newPriority) {

ThreadGroup g;

checkAccess();

if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {

throw new IllegalArgumentException();

}

if((g = getThreadGroup()) != null) {

if (newPriority > g.getMaxPriority()) {

newPriority = g.getMaxPriority();

}

setPriority0(priority = newPriority);

}

}

在Java中,线程的优先级分为【1~10】10个等级,从代码中我们也能看到,如果小于1或者大于10,则会抛出

IllegalArgumentException异常。

JDK中使用三个常量来预定义线程的优先级:

/**

* The minimum priority that a thread can have.

*/

public final static int MIN_PRIORITY = 1;

/**

* The default priority that is assigned to a thread.

*/

public final static int NORM_PRIORITY = 5;

/**

* The maximum priority that a thread can have.

*/

public final static int MAX_PRIORITY = 10;

线程优先级的特性:

继承性:比如A线程启动B线程,则B线程的优先级与A是一样的。设置A线程的优先级为6那么B线程也就是6。

规则性:线程优先级等级差距很大的时候,谁先执行完与代码的调用顺序无关。CPU尽量将资源让给优先级比较高的线程

随机性:优先级高的线程不一定每次都先执行完。优先级相近越能看出随机性。

优先级高的代码执行速度更快?

这是一个相对的问题,因为优先级高的会占用更多的时间片,相同的任务量能够更早的完成。或者说相同时间内可以完成更多的操作。但实际上CPU处理的速度是一样的。

9、守护线程

守护线程是一种特殊的线程,任何一个守护线程都是整个(没错是整个)JVM中所有非守护线程的“保姆”,只要当前JVM实例中存在任何一个非守护线程没有结束,守护线程就在工作,只有当最后一个非守护线程结束时,守护线程才能随着JVM一同结束工作。Daemon的作用就是为其他线程的运行提供便利服务,守护线程最经典的应用就是GC(垃圾回收器)。

让一个线程成为守护线程的方法是setDaemon(true);

java厨房_Java多线程基础相关推荐

  1. JAVA并发之多线程基础(2)

    除了我们经常用的synchronized关键字(结合Object的wait()和notify()使用)之外,还有对应的上篇文章讲到的方法JAVA并发之多线程基础(1)之外,我们日常中使用到最多的也就是 ...

  2. JAVA并发之多线程基础(5)

    上面介绍了并发编程中的栅栏等JAVA并发之多线程基础(4) .通过唯一的一个终点线来帮助确定线程是多晚开始执行下一次操作. LockSupport 提供了一个比较底层的线程挂起操作.有点类似于susp ...

  3. JAVA并发之多线程基础(4)

    继上篇文章JAVA并发之多线程基础(3)谈到的信号量以及读写锁之外,接下来就继续谈及JDK中并发类的操作. CountDownLatch 倒计时器是在某一些程序需要前置处理的时候完美搭档.例如我们经常 ...

  4. JAVA并发之多线程基础(3)

    上篇文章中讲到了重入锁以及对应的条件操作,详情见JAVA并发之多线程基础(2).这篇文章我们就继续谈JDK中含有的并发操作类. Semaphore 对于大部分的锁来说,线程之间的都是互斥的,排他的,只 ...

  5. java子线程的创建_Java多线程基础(一):线程的创建

    多线程基础 并行与并发 并发是指一个处理器同时处理多个任务. 并行是指多个处理器或者是多核的处理器同时处理多个不同的任务. 打个比方:在并发的状态下,餐厅里只有一个厨师,尽管他做事利索,餐厅的客人等待 ...

  6. Java并发编程-多线程基础

    Java多线程基础 1.多线程概述 实现线程的两种方式 继承Thread类 实现Runnable接口 2.线程生命周期 获取线程的名字和线程对象 3.线程的休眠 sleep方法 终止线程的休眠 强行终 ...

  7. 【Java程序设计】多线程基础

    多线程基础 文章目录 多线程基础 一.线程的概念 (1)进程 (2)线程 二.线程的创建 (1)Thread 1.Thread类 2.Thread类的子类来创建线程 3.在新线程中完成计算某个整数的阶 ...

  8. java mina多线程_Java多线程基础总结九:Mina窥探(1)

    一直以来的多线程的基础总结都是脱离应用的,但是要说多线程的应用就不能不说Mina.Apache Mina作为一个高性能的Java异步并发网 络通讯框架,其内部的多线程的设计和实现可谓是学习多线程的良药 ...

  9. java线程基础_Java多线程基础

    前言 在我们工作和学习的过程中,Java线程我们或多或少的都会用到,但是在使用的过程上并不是很顺利,会遇到各种各样的坑,这里我通过讲解Thread类中的核心方法,以求重点掌握以下关键技术点: 线程的启 ...

最新文章

  1. Java8的集合:ArrayList的实现原理
  2. mysql查询操作及正则表达式小结
  3. Python学习笔记:面向对象高级编程(中下)
  4. [转]asp.net导出数据到Excel的三种方法
  5. 什么是 css,关于css是什么
  6. (转)让思维活跃化的几个技巧
  7. OpenHarmony 1.1.0 LTS 版本发布,十六大性能全面提升
  8. Visual Basic编程常见问题及解答(3)
  9. MySQL数据库迁移
  10. js 栈 html标签修复,js 打印错误堆栈
  11. SysTrace常识
  12. mysql三张表 left join
  13. Named Route ‘layout‘ has a default child route. When navigating to this named route (:to=“{name: ‘l
  14. nmea-0183数据处理matlab,Matlab分析NMEA0183报文源代码(含高斯6度带投影计算)
  15. 限制p元素之显示2行文字,同时出现省略号。
  16. Android 下拉选择框自定义view
  17. 在 MaCA 根目录运行所有 py 文件
  18. 感知器算法(PLA)
  19. 折半查找法的两种实现
  20. rs232串口通讯模块 - Delphi编程

热门文章

  1. logging 日志输出乱码 info_接口自动化测试中logging实际用法
  2. 第三方软件源_手机上的天气软件哪个更准确?
  3. 01初识鸿蒙_移动通讯技术的发展
  4. java jmf 视屏监控的核心代码_JMF(Java Media Framework)使用摄像头
  5. javaweb上传文件_javaWeb中,如何通过CommonsFileUpload组件上传文件
  6. 事物 @Transactional
  7. Docker部署OpenProject
  8. 当同时使用bootstrap-datepicker.js和jquery.validate.js这两款插件,至少要选择两次时间,才能验证成功的问题...
  9. Mongodb 故障分享 初始化时errmsg : exception: new file allocation failure 并且长时间处于STARTUP2...
  10. Strom小实例,大小写转换