多线程详解.

编程入门 行业动态 更新时间:2024-10-28 10:23:41

<a href=https://www.elefans.com/category/jswz/34/1767532.html style=多线程详解."/>

多线程详解.

目录: 

一、什么是线程 

二、分析下列程序有几个线程

三、实现线程的第一种方式
    —— 第二种方式(建议使用第二种方式)
    —— 采用匿名内部类格式

四、线程的生命周期

五、获取线程的名字
    —— 获取当前线程对象

六、线程的sleep方法
    —— 关于Thread.sleep方法的一个面试题
    —— 终止线程的睡眠
    —— 合理的终止一个线程的执行【重点 常用】

一、什么是线程 

1.1、什么是进程?什么是线程?
    进程是一个应用程序(1个进程是一个软件)。
    线程是一个进程中的执行场景/执行单元。
    一个进程可以启动多个线程。
1.2、对于java程序来说,当在Dos命令窗口中输入
    java HelloWorld 回车之后。
    会先启动JVM,而JVM就是一个进程。
    JVM再启动一个主线程调用main方法。
    同时再启动一个垃圾回收线程负责看护,回收垃圾。
    最起码,现在的java程序中至少有两个线程并发,
    一个是垃圾回收线程,一个是执行main方法的主线程。
1.3、进程和线程是什么关系?举个例子
    阿里巴巴:进程
        马云:阿里巴巴的一个线程
        童文红:阿里巴巴的一个线程
    京东:进程
        强东:京东的一个线程
        妹妹:京东的一个线程
    进程可以看做是现实生活当中的公司。
    线程可以看做是公司当中的某个员工。

    注意:
    进程A和进程B的内存独立不共享。(阿里巴巴和京东资源不会共享的!)
    
    线程A和线程B呢?
    在java语言中:
    线程A和线程B,堆内存和方法区内存共享。
    但是栈内存独立,一个线程一个栈。
    假设启动10个线程,会有10个栈空间,每个栈和每个栈之间,
    互不干扰,各自执行各自的,这就是多线程并发。
    java中之所以有多线程机制,目的就是为了提高程序的处理效率。

1.4、思考一个问题:
使用了多线程机制之后,main方法结束,是不是有可能程序也不会结束?
    main方法结束只是主线程结束了,主栈空了,其它的栈(线程)可能还在
    压栈弹栈。|

4.5、分析一个问题:对于单核的CPU来说,真的可以做到真正的多线程并发吗?
    对于多核的CPU电脑来说,真正的多线程并发是没问题的。
    4核CPU表示同一个时间点上,可以真正的有4个进程并发执行。
    
    什么是真正的多线程并发?
        t1线程执行t1的。
        t2线程执行t2的。
        t1不会影响t2, t2也不会影响t1。这叫做真正的多线程并发

单核的cPU表示只有一个大脑:
不能够做到真正的多线程并发,但是可以做到给人一种"多线程并发"的感觉。
对于单核的CPU来说,在某一个时间点上实际上只能处理一件事情,但是由于
CPU的处理速度极快,多个线程之间频繁切换执行,跟人来的感觉是:多个事情
同时在做!!!!!
线程A:播放音乐
线程B:运行魔兽游戏
线程A和线程B频繁切换执行,人类会感觉音乐一直在播放,游戏一直在运行 ,
给我们的感觉是同时并发的。

二、分析下列程序有几个线程

代码演示:

package com.bipowernode.javase.thread;
/*分析以下程序,有几个线程,除垃圾回收线程之外有几个线程?1个线程(因为程序只有一个栈)输出结果:main beginm1 beginm2 beginm3 execute~m2 overm1 overmain over一个栈中,自上而下依次逐行执行~*/
public class ThreadTest01 {public static void main(String[] args) {System.out.println("main begin");m1();System.out.println("main over");}private static void m1() {System.out.println("m1 begin");m2();System.out.println("m1 over");}private static void m2(){System.out.println("m2 begin");m3();System.out.println("m2 over");}private static void m3(){System.out.println("m3 execute~");}
}

三、实现线程的第一种方式

代码演示: 

package com.bipowernode.javase.thread;
/*
实现线程的第一种方式:编写一个类,直接继承java.lang.Thread, 重写run方法以下程序的输出结果有这样的特点:有先有后有多有少这是咋回事?因为底层主线程和子线程进入到就绪状态(start)的时候:具有抢夺CPU时间片的权力,当一个线程抢到CPU时间片后就开始run()方法进入运行状态 【谁先抢到谁准备进入运行状态】*/
public class ThreadTest02 {public static void main(String[] args) {// 这里是main方法,这里的代码属于主线程,在主栈中运行// 新建一个分支线程对象MyThread t =new MyThread();// 启动线程// start()方法的作用是:启动一个分支线程,在JVM中开辟一个新的栈空间,这段代码认为完成之后,瞬间就结束了(瞬间结束之后开始主线程代码跑动)// 这段代码的任务只是为了开辟一个新的栈空间,只要新的栈空间开辟出来,start()方法就瞬间结束,线程就启动成功了// 启动成功的线程会自动调用run方法,并且run方法在分支栈的栈底部(压栈)// run方法在分支栈的栈底部,main方法在主栈的栈底部,run和main是平级的t.start();// 这里的代码还是运行在主线程中for (int i =0;i<=1000;i++){System.out.println("主线程----> "+i);}}
}class MyThread extends Thread{// 重写 run方法@Overridepublic void run() {// 编写程序,这段程序运行在分支线程中(分支栈)for (int i=0; i<=1000;i++){System.out.println("分支线程----> "+i);}}
}

输出结果:

 注意:

package com.bipowernode.javase.thread;
/*
实现线程的第一种方式:编写一个类,直接继承java.lang.Thread, 重写run方法*/
public class ThreadTest02 {public static void main(String[] args) {// 这里是main方法,这里的代码属于主线程,在主栈中运行// 新建一个分支线程对象MyThread myThread =new MyThread();// 如果这里直接调用分支线程的run方法myThread.run(); // 那么这里就相当于调用了一个类当中的普通方法,没有开启分支线程,只是把run()这个方法通过压栈的方式到了main方法中// 这样写只有一个主线程 // 会先把run()方法当中的程序跑完之后弹栈后再执行main方法当中的代码程序// 这里的代码还是运行在主线程中for (int i =0;i<=1000;i++){System.out.println("主线程----> "+i);}}
}class MyThread extends Thread{    // 缺点该类不能再继承其他的类了// 重写 run方法@Overridepublic void run() {// 编写程序,这段程序运行在分支线程中(分支栈)for (int i=0; i<=1000;i++){System.out.println("分支线程----> "+i);}}
}

内存图演示如下:

第二种方式(建议使用第二种方式)


1、实现线程的第二种方式:编写一个类实现java.lang.Runnable接口
2、建议使用接口方式
    因为子线程实现Runnable方法后 还可以去继承其他的类 更加灵活 扩展性强

代码演示如下: 

package com.bipowernode.javase.thread;
/*
1、实现线程的第二种方式:编写一个类实现java.lang.Runnable接口
2、建议使用接口方式因为子线程实现Runnable方法后 还可以去继承其他的类 更加灵活 扩展性强*/
public class ThreadTest03{public static void main(String[] args) {// 创建一个可运行对象// MyRunnable r =new MyRunnable();// 将可运行对象封装成一个线程对象// Thread t =new Thread(r);Thread t =new Thread(new MyRunnable()); // 合并代码// 启动线程t.start();for (int i=0;i<=100;i++){System.out.println("主线程===="+i);}}
}// 这里并不是一个线程类,是一个可运行的类,它还不是一个线程
class MyRunnable implements Runnable{    // 该类还可以继续继承其他的类 扩展性强了// 实现该方法@Overridepublic void run() {for (int i=0;i<=100;i++){System.out.println("分支线程===="+i);}}
}

采用匿名内部类格式

代码演示:

package com.bipowernode.javase.thread;
// new个接口 加个实现类
public class ThreadTest04 {public static void main(String[] args) {// 创建线程对象,采用匿名内部类的格式// new Runnable(){}  相当于new了一个匿名类,这个匿名类实现了Runnable接口Thread thread =new Thread(new Runnable(){@Overridepublic void run() {// 分支线程for (int i=0;i<=100;i++){System.out.println("分支进程----> "+i);}}});// 启动线程thread.start();// 主线程for (int i=0;i<=100;i++){System.out.println("子线程----> "+i);}}
}

 四、线程的生命周期

五、获取线程的名字

代码演示如下:

package com.bipowernode.javase.thread;
/*
1、怎么获取当前线程对象?static native Thread currentThread(); 方法
2、获取线程对象的名字String name =线程对象.getName();3、修改线程对象的名字线程对象.setName("线程名字");4、当线程没有设置名字的时候,默认的名字有什么规律:Thread-0Thread-1Thread-2Thread-3Thread-4....*/
public class ThreadTest05 {public static void main(String[] args) {// 创建线程对象MyTread1 t =new MyTread1();// 设置线程的名字t.setName("线程t");// 获取线程的名字System.out.println(t.getName());    // 线程t// 创建线程对象MyTread1 tt =new MyTread1();// 设置线程名字tt.setName("tt线程");System.out.println(tt.getName());// 开启线程t.start();tt.start();}
}class MyTread1 extends Thread {@Override   // 重写run方法public void run() {for (int i = 0; i <= 100; i++) {System.out.println("分支线程---->" + i);}}
}

 

 

5.1、获取当前线程对象

代码演示如下:

package com.bipowernode.javase.thread;
/*
1、怎么获取当前线程对象?static native Thread currentThread(); 方法*/
public class ThreadTest05 {public static void main(String[] args) {// currentThread就是当前线程对象// 这个代码出现在main方法当中,所以当前线程是主线程Thread currentThread =Thread.currentThread();System.out.println(currentThread.getName());// 创建线程对象MyTread1 t =new MyTread1();// 设置线程的名字t.setName("线程t");MyTread1 tt =new MyTread1();// 设置线程名字tt.setName("tt线程");// 开启线程t.start();tt.start();}
}class MyTread1 extends Thread {@Override   // 重写run方法public void run() {// currentThread就是当前线程对象,当前线程是谁呢?// 当t1线程执行run方法的时候,那么这个当前线程就是t1// 当tt线程执行run方法的时候,那么这个当前线程就是ttThread currentThread =Thread.currentThread();for (int i = 0; i <= 100; i++) {System.out.println(currentThread.getName() +"===>" + i);}}
}

六、线程的sleep方法

关于线程的sleep方法
    static void sleep(long millis)
    1、静态方法
    2、参数是毫秒
    3、作用:让当前线程进入休眠,进入”阻塞状态“,放弃占有的时间片,让给其他线程用

代码演示如下: 

package com.bipowernode.javase.thread;
/*
关于线程的sleep方法static void sleep(long millis)1、静态方法2、参数是毫秒3、作用:让当前线程进入休眠,进入”阻塞状态“,放弃占有的时间片,让给其他线程用*/
public class ThreadTest06 {public static void main(String[] args)  {// 让当前线程进入休眠,睡眠5s(当前线程是main主线程)try {Thread.sleep(1000*5);} catch (InterruptedException e) {e.printStackTrace();}// 5s后执行这里的代码System.out.println("hello world");for (int i=0;i<=9;i++){// 每输出一次 睡眠1sSystem.out.println(Thread.currentThread().getName() +"---->" +i);// 睡眠1stry {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

输出结果:

 关于Thread.sleep方法的一个面试题

package com.bipowernode.javase.thread;/*
关于Thread.sleep()方法的一个面试题:*/
public class ThreadTest07 {public static void main(String[] args) {// 创建线程对象MyThread2 t =new MyThread2();// 设置线程名字t.setName("线程t");// 开启线程t.start();// 调用sleep方法try {// 问题:这行代码会让线程t进入休眠状态吗?t.sleep(1000*5);        // 在执行的时候还是会转换成:Thread.sleep(1000*5);} catch (InterruptedException e) {  // 因为sleep的作用是让当前线程进入睡眠状态 此代码当中当前线程是main线程 【注意是当前线程进入睡眠状态】e.printStackTrace();}// 主线程代码// 5s后执行主线程System.out.println("我是5s后才被执行的主线程代码~");}
}class MyThread2 extends Thread{@Overridepublic void run() {// 这里跑的是分支线程for (int i=0;i<=1000;i++){System.out.println(Thread.currentThread().getName() +"---->" +i);}}
}

终止线程的睡眠

interrupt()方法  这种终断睡眠的方式依靠了java的异常处理机制

package com.bipowernode.javase.thread;
//sleep睡眠太久了,如果希望半道上醒来,你应该怎么办? 也就是说怎么叫醒一个正在睡眠的线程????public class ThreadTest08 {public static void main(String[] args) {// 创建线程对象Thread t =new Thread(new MyThread0());// 设置线程的名字t.setName("线程t");t.start();// 假设半小时过去了,让t线程醒来(半小时后主线程手里头的活干完了 )// 终止t线程的睡眠t.interrupt();  // 干扰作用// 这种终断睡眠的方式依靠了java的异常处理机制(通过干扰t线程当中的异常报错然后捕获异常 异常分支结束,继续往下走分支"----> end")}
}class MyThread0 implements Runnable{// 实现run()方法// 重点:run()方法当中的异常不能throws,只能try....catch// 因为run()方法在父类Runnable中没有抛任何异常,子类不能比父类抛出更多的异常@Overridepublic void run() {// 这里跑的是子线程的代码System.out.println(Thread.currentThread().getName()+"---> begin~");// 睡眠一小时try {Thread.sleep(1000*60*60*60); // 谁调用start进入run()方法谁就是当前线程} catch (InterruptedException e) {// 打印异常信息(可省略掉 就不会打印异常信息了)// e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"----> end");}
}

 例子演示:

package com.bipowernode.javase.thread;public class A {public static void main(String[] args) {// 创建线程对象Thread t =new Thread(new Runnable() {@Overridepublic void run() {// 这里走的是子线程分支// 先睡眠1h 让主线程先完成任务再开启try {   // 这里只能try catch 因为父类当中的run方法没有任何异常 子类不能比父类抛出更多的异常Thread.sleep(1000*60*60*60);} catch (InterruptedException e) {// e.printStackTrace();System.out.println("子线程睡眠干扰成功");}for (int i=0;i<=900;i++){System.out.println(Thread.currentThread().getName()+"---->" +i);   // 谁调用这就是哪个线程的名字}}});// 设置线程名字t.setName("线程t");// 开启线程t.start();// 主线程for (int i=0;i<=900;i++){System.out.println(Thread.currentThread().getName()+"---->"+ i);}// 主线程结束之后 开启子线程t.interrupt();  // 干扰的是异常}
}

输出结果:

 合理的终止一个线程的执行【重点 常用】

package com.bipowernode.javase.thread;// 合理的终止一个线程的执行  这是一个很常用的方式
public class ThreadTest09 {public static void main(String[] args) {MyThread01 m =new MyThread01();// 创建线程对象Thread t =new Thread(m);// 设置线程名字t.setName("线程t");// 开启线程t.start();// 模拟5s 假设5s后终止线程的执行 (这里跑的程序 是主线程)try {Thread.sleep(1000*5);} catch (InterruptedException e) {e.printStackTrace();}m.run =false;}
}class MyThread01 implements Runnable{// 打一个布尔标记boolean run =true;@Overridepublic void run() {for (int i=0;i<=9;i++){if (run){// 睡眠一秒try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"---->"+i); // 每睡眠一秒执行一次}// 程序到这里说明falseelse {// 终止线程程序// return 就结束了 你在结束之前还有什么没保存的// 在return之前可以进行保存return;}}}
}

 

更多推荐

多线程详解.

本文发布于:2024-03-13 11:00:58,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1733841.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:多线程   详解

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!