Java基础知识盘点(三)- 线程篇
创建线程的方式及实现
一、继承Thread类创建线程类
1、定义Thread的子类,并重写run方法,因为该方法的方法体就是代表了线程要完成的任务,因此run方法又叫做执行体。
2、创建Thread子类的实例,即创建了线程对象。
3、调用线程对象的start方法来启动该线程。
二、通过Runnable接口来创建线程类
1、定义Runnable接口的实现类,并重写run方法,跟Thread一样,该run方法又叫做执行体。
2、创建实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的对象。
3、调用线程对象的start方法来启动该线程。
三、通过Callable和Future创建线程
1、创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
2、创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
3、使用FutureTask对象作为Thread对象的target创建并启动新线程。
4、调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
创建线程的三种方式的对比
采用实现Runnable、Callable接口的方式创见多线程时
优势是:
线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。
在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
劣势是:
编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。
使用继承Thread类的方式创建多线程时优势是:
编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。
劣势是:
线程类已经继承了Thread类,所以不能再继承其他父类。
sleep()、join()、yield()区别
1、sleep()
在指定毫秒数为单位,让当前正在执行的线程处于休眠状态,但此操作并不会释放对象锁。
2、yield()
它与sleep类型,也不会释放锁,但它没有参数,即yield()方法只是使当前线程重新回到可执行状态。该方法只能使同优先级或高优先级的线程得到执行机会,这也和sleep方法不同。
3、join()
Thread的非静态方法join()让一个线程B“加入”到另外一个线程A的尾部。在A执行完毕之前,B不能工作。
sleep()和wait()的区别
1、对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的
2、sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态
3、在调用sleep()方法的过程中,线程不会释放对象锁
4、而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。
CountDownLatch 原理
CountDownLatch是同步工具类之一,可以指定一个计数器,在并发环境下由线程进行减1操作,当计数器变为0时,被await方法阻塞的线程将会被唤醒,实现线程间的同步。
CyclicBarrier 原理
字面意思是可循环(Cyclic)使用的屏障(Barrier)。它要做的事情是让一组线程到达一个屏障(同步点)时被阻塞,直到最后一个线程到达屏障时候,屏障才会开门。所有被屏障拦截的线程才会运行。
说说Semaphore原理
信号量,用来控制多线程同时访问特定资源时的线程数量,它通过协调合理的使用公共资源。线程通过acquire方法活动信号量的许可,当信号量没有可用的许可的时候,线程阻塞,直到有可用的线程为止。线程可以通过releace方法来释放它持有的信号量许可。
说说 Exchanger 原理
JDK1.5提供的工具套件,用来处理两个线程之间的数据交换。
ThreadLocal 原理分析
线程局部变量,并发的时候成员变量是不安全的,因为同时有多个线程在访问,我们需要满足这样一个条件:变量是同一个,但是每个线程都使用同一个初始值,也就是使用同一个变量的一个新的副本,当我们调用get方法的时候,其实每个当前线程中都有一个ThreadLocal。每次获取或者设置都是对该ThreadLocal进行的操作,是与其他线程分开的。
线程池的几种方式
1、newFixedThreadPool(int nThreads):创建一个固定长度的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程的规模将不再变化,当线程发生未预期的错误而结束时,线程池会补充一个新的线程
2、newCachedThreadPool():创建一个可缓存的线程池,如果线程池超过了处理需求,将自动回收线程池,而当需求增加时,则可以自动添加新线程,线程池的规模不存在任何限制
3、newSingleThreadExecutor():单线程的Executor,它创建单个工作线程来执行任务,如果这个任务异常结束,会创建一个新的来替代它,它的特点是能确保依照任务在队列中的顺序来串行执行
4、newScheduledThreadPool(int corePoolSize):创建一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer。
线程的生命周期
新建(new)、就绪(Runnable)、运行(Running)、阻塞(Blockde)、死亡(Dead)
新建(new Thread):当创建Thread类的实例对象时,此线程进入新建状态(未被启动)
就绪(Runnable):线程被启动,正在序列队列中等待被分配给CPU资源
运行(Running):线程获得了CPU资源,正在执行任务(run()方法),运行中除非该线程自动放弃CPU资源或有更高优先级的线程进入,否则它将一直执行下去到任务结束。
死亡(dead):该线程执行完毕后或被其他线程杀死,线程就进入到了死亡状态,此时线程不可能再进入等待执行状态
阻塞(Blocked):由于某些原因导致该线程让出CPU并暂停自己的执行。
锁机制
说说线程安全问题
线程安全是指要控制多个线程对某个资源的有序访问或修改,而在这些线程之间没有产生冲突。
线程安全一般体现在两个方面:
1、多个Thread对同一个实例的访问(read和modify)不会相互干扰,它主要体现在关键字synchronized上。如ArrayList和Vector,HashMap和HashTable(后者每个方法前都有synchronized关键字)
2、每个线程都有自己的字段,而不会在多个线程之间共享。它主要体现在java.lang.ThreadLocal类,而没有java关键字支持,如static、transient那样。
悲观锁 乐观锁
悲观锁:总是假设最坏的情况,每次取数据时都认为其他线程会修改,在Java中,synchronized的思想也是悲观锁。
乐观锁:总是认为不会产生并发问题,每次取数据的时候总是认为不会被其他线程修改,但是在更新时会判断其他线程在这之前有没有对数据进行修改,一般会使用版本号机制或CAS操作实现
1、version方式:一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功
2、CAS操作方式:即compare and swap 或者 compare and set,涉及到三个操作数,数据所在的内存值,预期值,新值。当需要更新时,判断当前内存值与之前取到的值是否相等,若相等,则用新值更新,若失败则重试,一般情况下是一个自旋操作,即不断的重试。
Java基础知识盘点(三)- 线程篇的更多相关文章
- Java基础知识回顾之七 ----- 总结篇
前言 在之前Java基础知识回顾中,我们回顾了基础数据类型.修饰符和String.三大特性.集合.多线程和IO.本篇文章则对之前学过的知识进行总结.除了简单的复习之外,还会增加一些相应的理解. 基础数 ...
- Java基础知识盘点(一)- 基础篇
基本功 面向对象特征 封装.继承.多态和抽象 1.封装:给对象提供了隐藏内部特性和行为的能力.对象提供一些能被其他对象访问的方法,来改变它内部的数据. 在Java中,其访问权限有3种修饰符:publi ...
- Java基础知识盘点(二)- 集合篇
List和Set区别 List和Set都是继承Collection接口 List特点:元素有放入顺序,元素可重复 Set特点:元素无放入顺序,元素不可重复 Set和List对比: Set:检索元素效率 ...
- java 基础知识(三)
Arraylist与Vector的区别 清浅池塘 程序员,专栏:Java那些事儿唯一作者,咨询前请先点详细资料 162 人赞同了该文章 这几天工作有点忙,有很多代码需要写,更新文章有点慢,说声抱歉 ...
- Java基础知识(三)
一.hashCode 与 equals (重要) 面试官可能会问你:"你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?" 1 ...
- JAVA基础知识之多线程——线程池
线程池概念 操作系统或者JVM创建一个线程以及销毁一个线程都需要消耗CPU资源,如果创建或者销毁线程的消耗源远远小于执行一个线程的消耗,则可以忽略不计,但是基本相等或者大于执行线程的消耗,而且需要创建 ...
- JAVA基础知识之多线程——线程通信
传统的线程通信 Object提供了三个方法wait(), notify(), notifyAll()在线程之间进行通信,以此来解决线程间执行顺序等问题. wait():释放当前线程的同步监视控制器,并 ...
- java基础知识总结8(数据库篇1)
一. Oracle的安装(windowXP.win7.Linux)和卸载 1.1 Oracle的安装 1.1.1 在WindowsXP.Win7下安装 第一:解压win32_11gR2_databas ...
- java基础知识(三)java关键字
关键字是电脑语言事先定义的,是特别意义的标识符,又叫保留字.用来表示一种数据类型或程序的结构等,关键字不能用作变量名.类名.方法名或参数.java目前共有50个关键字,其中"const&qu ...
随机推荐
- MySQL中的EXPLAIN
使用EXPLAIN加上SELECT语句可以获取优化器的查询执行计划 MySQL会在查询上设置一个标记,当执行查询时,这个标记会返回关于在执行计划中每一步的信息,而不是执行它.它会返回一行或多行信息,一 ...
- Python3学习之路~8.6 开发一个支持多用户在线的FTP程序-代码实现
作业: 开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp s ...
- Pocket Gem OA: Path Finder
1. 有向图 找所有start node到end node之间的路径 输入是一个txt 形式如下: A E A : B C D. B : C C : E D : B. 输出一个List<Stri ...
- 爬虫-----爬取所有国家的首都、面积 ,并保存到txt文件中
# -*- coding:utf-8 -*- import urllib2import lxml.htmlfrom lxml import etree def main(): file = open( ...
- Sublime 个人常用快捷键
Sublime 个人常用快捷键 Hot Key Alt + F3 选中文本所以有相同项;同多次Ctrl + D Ctrl + L 选中整行,继续按可继续选 Ctrl + Shift + M 选择括号内 ...
- Firefox 安装 Adobe Flashplayer
3. 安装Adobe Flash Player: Adobe Flash Player的安装比较容易,只要将对应的文档复制到正确的的位置即可,具体的操作 如下: (1) 将libflashplayer ...
- servlet中如何实现通过Spring实现对象的注入
@WebServlet("/BaseServlet")public class BaseServlet extends HttpServlet { private static f ...
- Docker学习资源
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口. ...
- python 对excel操作用法详解
在python中,对excel表格读,写,追加数据,用以下三个模块: 1.wlrd 读取excel表中的数据 2.xlwt 创建一个全新的excel文件,然后对这个文件进行写入内容以及保存. 3.xl ...
- 对接 第三方物流APP 手机版
昨天因为bibi项目要对接 物流信息 开始找了快递鸟文档,但是要填写申请APP,必须要注册公司才可以,这样非常麻烦.下面的第三方物理接口,绝对让你满意. https://m.kuaidi100.com ...