java 多线程详细笔记(原理理解到全部使用)
鸽了好久以后终于又更新了,看同学去实习都是先学源码然后修改之类,才发觉只是知道语法怎么用还远远不够,必须要深入理解以后不管是学习还是工作,才能举一反三,快速掌握。
基础知识
既然说到了多线程,那自然就要了解一下线程到底是什么,计算机又是怎么实现对应功能的呢。
进程与线程
进程: 是代码在数据集合的一次运行活动,是系统进行资源分配和调度的基本单位。我们常用的程序就是一个进程,像qq音乐、word之类,进程就是一个程序的动态执行过程。
线程: 线程是进程的一个组成部分,一个进程可以有多个线程,而一个线程只能属于一个进程。线程可以拥有自己的堆栈、自己的程序计数器还有自己的局部变量,但不能拥有系统资源。它与父进程的其他线程共享该进程的所有资源。就好比在使用word的时候,可以一遍打字,word自动统计字数、提示语法错误等,这些功能都属于一个线程。
但其实我们电脑中存在的线程数,要远远大于电脑cpu的个数,如果是单cpu的电脑的话,每一时刻就只有一个线程可以执行,但我们仍然可以实现很多程序的同时使用,其实我们所看到的多线程的运行,只是电脑在极短时间里交替执行多个线程所表现出来的效果,比如我在一边使用word,还一边听歌,那电脑可以每隔1ms播放一下音乐,再接受一下输入,再检测一下字数等,这样以极快的速度处理每个线程的部分代码,从而使得多个任务看起来可以"同时"进行。
多线程的确可以为我们处理任务提供很大的便利,提高效率,但是因为多线程的机制使得很多在单线程中正常执行的程序出现问题,其中包括:1、原子性问题 2、线程共享内存不可见的问题。
线程原子性问题
此问题经常出现在多个线程对同一组共享变量的访问中,假设有三个线程,每个线程都会使共享变量x减少1并打印,那么应该有如下示意图:
但因为执行的操作 x -= 1 实际上并不是一个操作,执行过程是获得现有x,创建一个新的变量x',然后另x'的数值变为x - 1,之后再将公共变量中x的指针指向新的变量x',从而实现对应操作。这样的非原子性的操作就会出现这样的情况:当A线程在获得了x,并且执行x-1以后,还没有将公共变量指针指向新的变量x'的时候,线程B进入并且也获得了x,此时线程B获得的x就还是没有更新的x,从而造成了数据读写不一致的问题。
线程共享内存不可见问题
出现不可见性问题的原因与线程访问共享数据方式有关,每一个线程都有单独的堆栈、程序计数器等信息,当线程要读取公共变量的时候,也是先读取到自己的栈中,然后进行操作,最后写回到进程的公共变量里去,但若在线程A将变量加入自己的栈后,线程B将修改后的结果写回公共变量,但此时线程A不知道公共变量已经修改,从而造成不一致问题。
基于这些问题,我们可以使用synchronized 以及volatile 关键字来进行避免,这些将在下一篇单独讲解。
线程状态介绍
线程共有五种状态,分别是新建状态(NEW),可运行状态(RUNNABLE), 运行状态(RUNNING),阻塞状态(BLOCKED),死亡状态(DEAD).现对其一一介绍:
新建状态
新建状态(NEW):指新创建了一个线程对象。
可运行状态
可运行状态(RUNNABLE):指有资格可以运行,但是没有获得cpu,所以要等待直到获得cpu后变成运行状态(RUNNING)。
有很多方法可以使线程变成可运行状态,譬如:
1、对新建立的线程执行start()方法。
2、对线程调用sleep()方法使之变为阻塞状态,当sleep时间过后,会恢复成可运行状态。
3、在本线程使用join()方法,当指定线程执行完毕后,本线程恢复为可运行状态。
4、使用yield()方法,进入可运行状态。
运行状态
运行状态就是线程获得了cpu,并执行对应代码。
阻塞状态
阻塞状态是程序让出cpu控制权,并且暂时停止运行。直到指定条件达成以后,有资格运行,变成可运行状态。
使程序进入阻塞状态的方法有:
1、等待阻塞:使用wait()方法,直到被notify()方法唤醒
2、同步阻塞:申请的资源上锁并被其他资源占用,此时阻塞直到对象锁被释放
3、其他阻塞:比如使用join()方法,则当前线程会阻塞直到指定线程完成。使用sleep()等待进入阻塞状态,直到等待时间后恢复。等待io处理等。
死亡状态
一般是因异常退出了run(),或者程序执行完成
多线程使用方法
如果只是单纯地使用多线程而不是深究其同步问题的话,java提供的Thread类是已经足够使用的,而对于同步问题的解决,将会在下一篇中进行详细分析与介绍。
线程的创建
可以使用两种方法来创建线程,分别是继承Thread并重写run()方法,或者实现Runable接口的run()方法,因为java不支持多继承,因此推荐使用实现接口的方式.
可以采用接口实现:
//使用接口实现
public class MyThread implements Runnable {
@Override
public void run() {
System.out.println("run!");
}
}
也可以使用继承的方式实现:
public class MyThread02 extends Thread {
@Override
public void run() {
System.out.println("i am running!");
}
}
线程的运行
调用start()方法即可运行。虽然我们写的是run()方法,但不要直接调用run()方法,那样就起不到多线程的作用了,应该调用start()方法,然后会将该线程变为可运行状态,根据启动条件和cpu情况,适时地执行程序。
线程的礼让
使用yield()方法,使线程让出cpu,重新回到可运行状态。这时候会继续争夺cpu,也就是有可能线程A使用yield()方法让出cpu以后,又重新获得cpu的使用资格。也就是如果有A、B两个线程,并不一定A线程礼让的时候,B线程一定先于A线程执行。
线程的睡眠
使用sleep()方法,使线程阻塞一定时间。
线程的join
使用threadx.join()方法,使得当前线程堵塞,直到threadx线程执行完成。
线程的等待与唤醒
一般都与锁一起使用。
java 多线程详细笔记(原理理解到全部使用)的更多相关文章
- java多线程学习笔记——详细
一.线程类 1.新建状态(New):新创建了一个线程对象. 2.就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中, ...
- Java多线程学习笔记--生产消费者模式
实际开发中,我们经常会接触到生产消费者模型,如:Android的Looper相应handler处理UI操作,Socket通信的响应过程.数据缓冲区在文件读写应用等.强大的模型框架,鉴于本人水平有限目前 ...
- JAVA多线程学习笔记(1)
JAVA多线程学习笔记(1) 由于笔者使用markdown格式书写,后续copy到blog可能存在格式不美观的问题,本文的.mk文件已经上传到个人的github,会进行同步更新.github传送门 一 ...
- Java多线程学习笔记(一)——多线程实现和安全问题
1. 线程.进程.多线程: 进程是正在执行的程序,线程是进程中的代码执行,多线程就是在一个进程中有多个线程同时执行不同的任务,就像QQ,既可以开视频,又可以同时打字聊天. 2.线程的特点: 1.运行任 ...
- Java多线程学习笔记——从Java JVM对多线程数据同步的一些理解
我们知道在多线程编程中,我们很大的一部分内容是为了解决线程间的资源同步问题和线程间共同协作解决问题.线程间的同步,通俗我们理解为僧多粥少,在粥有限情况下,我们怎么去防止大家有秩序的喝到粥,不至于 ...
- Java 多线程学习笔记:生产者消费者问题
前言:最近在学习Java多线程,看到ImportNew网上有网友翻译的一篇文章<阻塞队列实现生产者消费者模式>.在文中,使用的是Java的concurrent包中的阻塞队列来实现.在看完后 ...
- java多线程-读写锁原理
Java5 在 java.util.concurrent 包中已经包含了读写锁.尽管如此,我们还是应该了解其实现背后的原理. 读/写锁的 Java 实现(Read / Write Lock Java ...
- java多线程断点下载原理(代码实例演示)
原文:http://www.open-open.com/lib/view/open1423214229232.html 其实多线程断点下载原理,很简单的,那么我们就来先了解下,如何实现多线程的断点下载 ...
- java多线程学习笔记(三)
java多线程下的对象及变量的并发访问 上一节讲到,并发访问的时候,因为是多线程,变量如果不加锁的话,会出现“脏读”的现象,这个时候需要“临界区”的出现去解决多线程的安全的并发访问.(这个“脏读”的现 ...
随机推荐
- Exercise
""" 问:执行完下面的代码后, l,m的内容分别是什么? """ def func(m): for k,v in m.items(): m ...
- 关于“xxx”object is not callable的异常
参考博文:https://blog.csdn.net/yitiaodashu/article/details/79016671 所谓callable对象是指一个后边可以加()的对象,比如函数, 所以这 ...
- python正则表达式详解之Match类及其方法
1.Match对象简介 match对象通常是由正则表达式对象的match 方法,search 方法等经过匹配之后而产生.可以直接当做bool值使用,如果匹配则相当于True, 如果不匹配,则返回Non ...
- Jmeter:运行报:Error occurred starting thread group :线程组, error message:Invalid duration 0 set in Thread Group:线程组, see log file for more details
最近在用jmeter做压测,上周五压测的脚本,今天早晨结束后. 点击同样的脚本,运行就报Error occurred starting thread group :线程组, error message ...
- thinkphp5.1+layui2.x 时间戳转换为日期格式
layui.use(['table','util'],function(){ var table = layui.table,form = layui.form; table.render({ ele ...
- Codeforces Round #632 (Div. 2) 题解
空山新雨后,天气晚来秋. 明月松间照,清泉石上流. 竹喧归浣女,莲动下渔舟. 随意春芳歇,王孙自可留.--王维 A. Little Artem 网址:https://codeforces.com/co ...
- Scala教程之:Scala基础
文章目录 常量 变量 代码块 函数 方法 类 case类 对象 trait main方法 这篇文章我们大概过一下Scala的基础概念,后面的文章我们会有更详细的讲解Scala的具体内容. 常量 在Sc ...
- 【集群实战】NFS服务常见故障排查和解决方法
NFS,全名叫Network File System,中文叫网络文件系统,是Linux.UNIX系统的分布式文件系统的一个组成部分,可实现在不同网络上共享远程文件系统. NFS由Sun公司开发,目前已 ...
- 【Linux常见命令】mkdir命令
mkdir - make directories 例子: mkdir /data 在根目录/下创建data文件夹(目录) 语法: mkdir [-p] dirName 参数说明: -p 确保目录名称存 ...
- Flex 布局教程:语法篇(转自阮一峰的网络日志)
作者:阮一峰(转自阮一峰的网络日志,如有侵权,立即删除) 网页布局(layout)是 CSS 的一个重点应用. 布局的传统解决方案,基于盒状模型,依赖 display 属性 + position属性 ...