Java多线程(全)学习笔记(上)
2019独角兽企业重金招聘Python工程师标准>>>
一.线程的创建和启动
java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。每条线程的作用是完成一定的任务,实际上就是执行一段程序流(一段顺序流的代码)。Java使用run方法来封装这样一段程序。
1.继承Thread类创建线程类
/**继承Thread来创建线程类*/
public class FirstThread extends Thread {
private int i;
//重写run方法,run方法的方法体就是线程执行体
public void run() {
for(;i<10;i++){
System.out.println(this.getName()+":"+i);
}
}
public static void main(String []args){
for(int i=0;i<20;i++){
System.out.println(Thread.currentThread().getName()+" .."+i);
if(i==10){
System.out.println("--------------------------------------------");
new FirstThread().start();
new FirstThread().start();
System.out.println("---------------------------------------------");
}
}
}
}
结果:红色部分每次运行都不一致,因为多线程也是并发的
main ..0
main ..1
main ..2
main ..3
main ..4
main ..5
main ..6
main ..7
main ..8
main ..9
main ..10
--------------------------------------------
Thread-0:0
---------------------------------------------
Thread-1:0
Thread-1:1
Thread-1:2
Thread-1:3
Thread-0:1
Thread-1:4
Thread-1:5
main ..11
Thread-1:6
Thread-1:7
Thread-1:8
Thread-1:9
Thread-0:2
Thread-0:3
main ..12
main ..13
......
总结 :从上面结果可以看出Thread-0和Thread-1两条线程输出的i变量都不连续(注意:i变量是FirestThread的实例属性,而不是局部变量,但因为程序每次创建线程都会创建一个FirstThread对象,所以Thread-0和Thread-1不能共享该实例属性)。
使用继承Thread类的方法来创建线程类,多条线程之间无法共享线程类的实例变量。
2.实现Runnable接口创建线程类
public class SecondThread implements Runnable {
private int i;
public void run() {
for(;i<20;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
public static void main(String [] args){
for(int i=0;i<20;i++){
System.out.println(Thread.currentThread().getName()+" .."+i);
if(i==10){
SecondThread st=new SecondThread();
//通过new Thread( Runable target,String name)来创建新线程
new Thread(st,"线程1").start();
new Thread(st,"线程2").start();
}
}
}
结果:红色部分每次运行都不一致,因为多线程也是并发的
main ..0
main ..1
main ..2
main ..3
main ..4
main ..5
main ..6
main ..7
main ..8
main ..9
main ..10
--------------------------------------------
线程1:0
--------------------------------------------
线程1:1
线程2:1
线程2:3
main ..11
线程2:4
线程2:5
线程2:6
线程1:2
线程2:7
线程2:9
线程2:10
线程2:11
线程2:12
线程2:13
main ..12
线程2:14
线程2:15
线程2:16
线程2:17
线程1:8
线程2:18
main ..13
main ..14
线程1:19
main ..15
main ..16
main ..17
。。。。
总结:根据源代码中Thread类构造方法 Ruanalbe接口对象target只能作为参数传递到Thread构造方法中,所以多个线程可以共用一个Runnable对象,因为都用同一个Runnable对象所以在Runnable实现类的实例变量也可以共享了。
所以Runable非常适合多个相同线程来处理同一份资源的情况。
二.线程的生命周期
1.New新建 :当线程被创建时,该线程处于新建状态,此时它和其他java对象一样,仅仅由Java虚拟机为其分配了内存,并初始化了其成员变量的值。(此时的线程没有表现出任何表现出任何线程的动态特征,程序也不会执行线程的线程执行体)new Thread()||new Thread(Runnable target,String name)。
2.Runnable就绪:就绪也就是说启动线程,但是启动线程使用start方法,而不是run方法!永远不要调用线程对象的run()方法!调用start方法来启动线程,系统会将该run方法当成线程执行体来处理。如果直接调用线程对象的run方法。则run方法会立即执行,且在这个run方法的执行体未执行结束前其他线程无法并发执行(即系统会将run方法当做一个普通对象的普通方法,而不是线程执行体对待)
附1:如果有一个主线程,一个子线程。当根据逻辑代码该调用子线程时不一定会立即调用,为了想在子线程start()后立即调用子线程,可以考虑使用Thread.sleep(1),这样会让当前线程(主线程)睡眠1毫秒,因为cpu在这1毫秒中是不会休息的,这样就会去执行一条处于就绪状态的线程。
附2:不能对已经处于就绪状态的线程,再次使用start()
3.Running 运行:当处于就绪状态时,该线程获得cpu,执行体开始运行,就处于运行状态了。
4.Blocked 阻塞:线程不可能一直处于运行状态(线程执行体足够短,瞬间就可以完成的线程排除),线程会在运行过程中需要被中断,因为是并发,目的是会让其他线程获得执行的机会,线程的调度细节取决于OS采用的策略。(抢占式调度xp win7 linux unix..)。如果是一些特殊的小型设备可能采用 协作式调度(只有线程自己调用它的sleep()或yield()才会放弃所占用的资源)。
5.Dead死亡:根据上图所示。测试测试某条线程是否已经死亡,可以调用线程对象的isAlive()方法,当线程处于就绪,运行,阻塞时,返回true。线程处于新建,死亡时返回false。
不能对已经死亡的线程调用start()方法使它重新启动,死亡就是死亡,是不能再次作为线程执行的。
当主线程结束时候,其他线程不受任何影响,并不会随之结束。一旦子线程启动起来后,它就拥有和主线程相同的地位,它不会受到主线程的影响。
三.控制线程
1.join线程:
让一个线程等待另一个线程完成的方法:join()。当在某个程序执行流中调用其他线程的join()方法,那该执行流对应的线程就会阻塞,知道被join()加入的join线程完成为止。join方法通常有使用线程的程序调用,将大问题划分成许多小问题,每个小问题分配一个线程。当所有的小问题都得到处理后,再调用 主线程来进一步操作(Thread t=new Thread();t.start();t.join简单来说就是加入到t线程。等t线程执行完成后才会返回出来执行线程。)
Join方法有三种重用形式:
Join():等待被join的线程执行完成
Join(long millis):等待join线程的时间最长为millis毫秒,如果在这个时间内,被join的线程还没有执行结束则不再等待)
Join(long millis,int nanos)千分之一毫秒(不用)
Code:
public class JoinThread implements Runnable{
@Override
public void run() {
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
public static void main(String [] args) throws InterruptedException{
//实例化一个Runnable
JoinThread jt=new JoinThread();
//创建一个线程
new Thread(jt).start();
for(int i=0;i<10;i++){
if(i==3){
Thread th=new Thread(jt);
//启动第二个线程
th.start();
//main的线程中调用了th线程的join方法
//让第二个线程执行完成后再执行main
th.join();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
结果:
Thread-0:0
Thread-0:1
Thread-0:2
main:0
main:1
Thread-0:3
main:2
Thread-0:4
Thread-1:0
Thread-1:1
Thread-1:2
Thread-1:3
Thread-1:4
main:3
main:4
main:5
main:6
main:7
main:8
main:9
2.后台线程:
Code:
public class DaemonThread implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
public static void main(String [] args){
//要将前台线程转换成后台线程,需要在该线程刚新建还未start()之前转换。main线程也是前台线程
//所有前台线程死亡时,后台线程也就随之死亡。
DaemonThread dt=new DaemonThread();
Thread td=new Thread(dt,"线程1");
System.out.println("main方法是否是后台线程"+Thread.currentThread().isDaemon());
System.out.println("td线程最初是否是后台线程"+td.isDaemon());
//指定td为后台线程
td.setDaemon(true);
System.out.println("td线程执行setDaemon方法后是否是后台线程"+td.isDaemon());
//就绪启动后台线程
td.start();
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
结果:只要前台线程结束,后台线程也会随之结束,并不是马上结束
main方法是否是后台线程false
td线程最初是否是后台线程false
td线程执行setDaemon方法后是否是后台线程true
main 0
main 1
线程1:0
线程1:1
main 2
线程1:2
线程1:3
main 3
线程1:4
线程1:5
main 4
线程1:6
线程1:7
线程1:8
线程1:9
线程1:10
线程1:11
线程1:12
线程1:13
3.线程睡眠:sleep
/** * 线程睡眠:sleep有两种重载形式: * static void sleep(long millis) * static void sleep(long millis,int nanos) * */
public class SleepThread {
public static void main(String [] args) throws InterruptedException{
for(int i=0;i<5;i++){
System.out.println("线程:"+Thread.currentThread().getName()+"当前时间:"+new Date());
//让当前线程暂停2秒
Thread.sleep(2000);
}
}
}
结果:
线程:main当前时间:Fri Nov 04 18:51:33 CST 2011
线程:main当前时间:Fri Nov 04 18:51:35 CST 2011
线程:main当前时间:Fri Nov 04 18:51:37 CST 2011
线程:main当前时间:Fri Nov 04 18:51:39 CST 2011
线程:main当前时间:Fri Nov 04 18:51:41 CST 2011
4.线程让步(yield)
/** * yield()方法是一个和sleep方法有点类似的静态方法。yield也可以让当前正在执行的线程暂停 * 但它不会阻塞该线程,它只是将该线程转入就绪状态。yield只是让当前线程暂停一会儿,让系统的 * 调度器重新调度一次(完全可能的情况是:当一个线程调用了yield方法暂停之后,线程调度器又马上 * 将其调度出来重新执行。) * 实际上,当前线程调用了yield方法后,只有优先级和当前线程相同,甚至优先级高于当前线程的处于 * 就绪状态的线程才会获得执行机会。 * */
public class YieldThread implements Runnable{
@Override
public void run() {
for(int i=0;i<50;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
if(i==20){
Thread.yield();
}
}
}
public static void main(String [] args){
//启动第一条子线程
Thread td1=new Thread(new YieldThread(),"线程1");
//最高级
//td1.setPriority(Thread.MAX_PRIORITY);
//启动第二条子线程
Thread td2=new Thread(new YieldThread(),"线程2");
//最低级
td2.setPriority(Thread.MIN_PRIORITY);
td1.start();
td2.start();
System.out.println(Thread.currentThread().getName());
}
}
总结:sleep和yield区别
A.sleep方法暂停当前线程后,会给其他线程执行机会,不会理会其他线程的优先级。而yield只会给优先级>=当前优先级的线程执行机会
B.Sleep方法会将线程转入阻塞状态,知道经过阻塞时间才会转入就绪状态。而yield是不会将线程转入阻塞状态的,它只是强制当前线程进入就绪状态。
C.Sleep会抛出InterruptedException异常。而yield没有声明任何异常
D.Sleep方法比yield方法有更好的移植性。
E.通常不依靠yield来控制并发线程控制
转载于:https://my.oschina.net/91jason/blog/295333
Java多线程(全)学习笔记(上)相关推荐
- java多线程JUC学习笔记
JUC(java.util.concurrent) 1.1 进程/线程 1.2并发/并行 并发编程:并发.并行 并发(多线程操作同一个资源) CPI一核,模拟出来多条线程,天下武功,唯快不破,快速交替 ...
- java多线程基础学习[狂神说java-多线程笔记]
java多线程基础学习 一.线程简介 1.类比 2.程序进程线程 3.线程的核心概念 二.线程的实现(重点) 调用方法与调用多线程的区别 Thread 类 1.thread使用方法 2. 代码实现 3 ...
- Java基础篇 学习笔记
List item Java基础篇 学习笔记 java基础篇 第1章 计算机.程序和java概述 学习笔记 1.1什么是计算机 简单来说:计算机就是 ' 存储 ' 和 ' 处理 ' 数据的电子设备. ...
- java/android 设计模式学习笔记(1)--- 单例模式
前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使 ...
- Linux与C++11多线程编程(学习笔记)
多线程编程与资源同步 在Windows下,主线程退出后,子线程也会被关闭; 在Linux下,主线程退出后,系统不会关闭子线程,这样就产生了僵尸进程 3.2.1创建线程 Linux 线程的创建 #inc ...
- java/android 设计模式学习笔记(1)---单例模式
前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使 ...
- java最全学习路线
java最全学习路线 java核心基础 JDK安装配置 数据类型和运算符 流程控制 数组 类和对象 封装继承多态 抽象类和接口 集合框架 泛型 实用类 IO流 多线程 反射 网络编程 XML解析 Ja ...
- [转]Java中文处理学习笔记——Hello Unicode
Java中文处理学习笔记--Hello Unicode 作者: 车东 Email: chedongATbigfoot.com/chedongATchedong.com 写于:2002/07 最后更新: ...
- Java中文处理学习笔记——Hello Unicode (转)
Java中文处理学习笔记--Hello Unicode (转)[@more@] Java中文处理学习笔记--Hello Unicode 作者: 车东 chedong@bigfoot.com 最后更新: ...
- Java中文处理学习笔记
Java中文处理学习笔记--Hello Unicode 作者: 车东 Email: chedongATbigfoot.com/chedongATchedong.com 写于:2002/07 最后更新: ...
最新文章
- eclipse配置struts.xml自动提示
- Python—程序设计:抽象工厂模式
- NUXT 入门第一课: 关于 Nuxt.js
- 从popup window出发做navigation
- 你所阅读的,决定你是什么样的人
- [C++11]常量表达式函数
- jaxb-xjc.jar_使用xjc在一秒钟内生成您的JAXB类
- perl语言之列表与数组
- raspberry 防火墙_用于数据科学,Linux防火墙,Raspberry Pi NAS,openmediavault,Syncthing,微服务等的Python库
- 百面机器学习—3.逻辑回归与决策树要点总结
- Mac盖上屏幕后外接屏幕持续黑画面的解决方法
- python数学建模|综合评价方法
- 机票预订系统活动图_机票预订系统UML讲解
- win10 软路由_千元完美的家用低功耗软路由:J4125 迷你电脑GK41开箱体验!又是播放器,也是服务型AIO!...
- 深度学习—利用TensorFlow2实现狗狗品种品种(mobilenet实现)
- linux usr/bin/和 usr/local/bin之间的关系,什么是软链接?
- coc跑团san数值规则_【规则】克苏鲁coc跑团游戏术语/黑话,第三篇教学。
- java中字段可以取名is开头吗
- 许三多:浮躁社会的反义词
- JZOJsenior3488.【NOIP2013模拟联考11】矩形(rect)
热门文章
- delhpi7 tcombobox清楚重复项_数据分析必须想清楚的两个概念:指标和维度
- java word转图片tiff_Word 2010中将文档保存为TIFF图片的方法
- java读取http文件内容_使用HTTP读取文件的第一部分
- activemq mysql 配置详解_activeMQ数据库配置
- 装了python3但在cmd里不识别,Pip无法识别安装命令(Windows 7,Python 3.3)
- 计算机应用技术重点学科,福州大学省级重点学科介绍:计算机应用技术(081203)...
- 论高校计算机信息管理能力的提升,论高校计算机信息管理能力的提升
- action链接html,如何使用@ html.actionlink删除链接文本
- Flask Oauth
- shell read