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多线程下的对象及变量的并发访问 上一节讲到,并发访问的时候,因为是多线程,变量如果不加锁的话,会出现“脏读”的现象,这个时候需要“临界区”的出现去解决多线程的安全的并发访问.(这个“脏读”的现 ...
随机推荐
- css3变形
CSS3变形--旋转 rotate() 旋转rotate()函数通过指定的角度参数使元素相对原点进行旋转.它主要在二维空间内进行操作,设置一个角度值,用来指定旋转的幅度.如果这个值为正值,元素相对原点 ...
- Display a QMessageBox from a QThread
Emit a signal. Since you cannot do UI stuff in a Qthread, instead send your message as an argument o ...
- diskpart 分区,挂载,和移除
list disk select disk 1 clean Create partition primary size=102400 active format quick list volume a ...
- gitlab环境部署
一:配置主机名 [root@localhost ~]# hostname gitlab[root@localhost ~]# bash 二:安装依赖包 [root@gitlab ~]# yum -y ...
- 【Linux网络基础】TCP/IP协议簇的详细介绍(三次握手四次断开,11种状态)
一.TCP/IP协议簇(DoD参考模型) 用于简化OSI层次,以及相关的标准. 传输控制协议(tcp/ip)簇是相关国防部DoD所创建的,主要用来确保数据的完整性以及在毁灭性战争中维持通信 是由一组不 ...
- Linux hostname主机名查看和设置
查询主机名: uname -n hostname [root@oldboy ~]# uname -n oldboy [root@oldboy ~]# hostname oldboy Linux操作系统 ...
- 获取系统DPI、系统显示比例等
using System; using System.Drawing; using System.Runtime.InteropServices; namespace XYDES { public c ...
- tr标签使用hover的box-shadow效果不生效
先说问题: 这是大致的HTML结构 <table cellpadding="0" cellspacing="0"> <thead> &l ...
- Axios 拦截器中添加headers 属性
描述: 已在网上查过怎么在 interceptors 中对header进行处理,// http request 拦截器 axios.interceptors.request.use( config = ...
- CF1288C-Two Arrays (DP)
You are given two integers n and m. Calculate the number of pairs of arrays (a,b) such that: the len ...