Java多线程
2023-12-15 10:48:40
Java多线程
Java
是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51
亿个
Java
虚拟机,
Java
仍是企业和开发人员的首选开发平台。
??
课程内容的介绍
1.
线程中的概念
2.
多线程的实现方式
3.
线程中的常用方法
4.
线程的生命周期
5.
线程同步
6.
其他
??
一、线程的相关概念
1.进程和线程
进程:一个独立的正在执行的程序。
线程:一个进程的最基本的执行单位,执行路径。
??
多进程:在操作系统中,同时运行多个程序。
????????多进程的好处:可以充分利用CPU
,提高
CPU
的使用率。
多线程:在同一个进程
(
应用程序
)
中同时执行多个线程。
????????多线程的好处:提高进程的执行使用率,提高了CPU
的使用率。
??
注意:
1.
在同一个时间点一个
CPU
中只可能有一个线程在执行。
2.
多线程不能提高效率、反而会降低效率,但是可以提高
CPU
的使用率。
3.
一个进程如果有多条执行路径,则称为多线程程序。
4. Java
虚拟机的启动至少开启了两条线程,主线程和垃圾回收线程。
5.
一个线程可以理解为进程的子任务。
? ??
? ?
二、线程的实现方式
线程
是程序中执行的线程。
Java
虚拟机允许应用程序同时执行多个执行线程。
??
1.第一种创建方式
实现的步骤:
1.
创建
Thread
类的子类
2.
重写
run
方法
3.
创建线程对象
4.
启动线程
??
案例代码
package com.bobo.thread;
public class ThreadDemo02 {
/**
* 线程的第一种实现方式
* 通过创建Thread类的子类来实现
* @param args
*/
public static void main(String[] args) {
System.out.println("main方法执行了1...");
// Java中的线程 本质上就是一个Thread对象
Thread t1 = new ThreadTest01();
// 启动一个新的线程
// start方法并不能直接开启一个新的线程,真正开启线程的是 CPU,
// 当CPU空闲或者分配到此任务的时候就会创建一个新的线程,然后执行run方法中的代码
t1.start();
// t1.start(); 线程不能够启动多次 IllegalThreadStateException
// 如果要创建多个线程,就创建多个Thread对象即可
Thread t2 = new ThreadTest01();
t2.start();
// t1.run(); // 这个是显示的调用Thread的run方法 并没有开启新的线程
for(int i = 0 ; i< 10 ; i++){
System.out.println("main方法的循环..."+i);
}
System.out.println("main方法执行结束了3...");
}
}
/**
* 第一个自定义的线程类
* 继承Thread父类
* 重写run方法
*/
class ThreadTest01 extends Thread{
/**
* 当线程启动的时候会执行run方法中的代码
*/
@Override
public void run() {
System.out.println("我们的第一个线程执行了2....");
for(int i = 0 ; i < 10 ; i ++){
System.out.println("子线程:"+i);
}
}
}
??
输出结果
main方法执行了1...
我们的第一个线程执行了2....
我们的第一个线程执行了2....
子线程:0
子线程:1
子线程:2
子线程:3
子线程:4
子线程:5
子线程:6
子线程:7
子线程:8
子线程:9
子线程:0
子线程:1
子线程:2
main方法的循环...0
main方法的循环...1
main方法的循环...2
main方法的循环...3
main方法的循环...4
main方法的循环...5
main方法的循环...6
main方法的循环...7
子线程:3
子线程:4
子线程:5
子线程:6
子线程:7
子线程:8
子线程:9
main方法的循环...8
main方法的循环...9
main方法执行结束了3...
??
通过输出结果我们也能看出来 子线程中的代码和主线程中的代码是
并行
执行的。
??
注意点:
1.
启动线程是使用
start
方法而不是
run
方法。
2.
线程不能启动多次,如果要创建多个线程,那么就需要创建多个
Thread
对象。
??
? ?
课堂案例
在主线程中打印
1
到
100
,然后创建一个子线程实现大文件的复制工作。
package com.bobo.thread;
import java.io.*;
public class ThreadDemo03 extends Thread{
/**
* 在主线程中打印1到100,然后创建一个子线程实现大文件的复制工作。
* @param args
*/
public static void main(String[] args) {
System.out.println("主线程开始了...");
// 创建线程对象
ThreadDemo03 t1 = new ThreadDemo03();
t1.start();
printNum(1,100);//主线程
System.out.println("主线程结束了...");
}
@Override //重写run方法,
public void run() {
long start = System.currentTimeMillis();
System.out.println("子线程开始文件复制...");
// 实现文件的复制
try {
copyFile(new File("D:/IO/TEST.png"),new File("D:/NewIO/TEST.png"));
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("子线程结束文件复制...耗时:" + (end-start));
}
/**
* 通过循环打印数字
* @param start
* @param end
*/
public static void printNum(int start , int end){
//通过循环打印数字
for (int i = start ; i <= end ; i ++){
System.out.print(i + "\t");
if(i % 5 == 0){
System.out.println();
}
}
}
/**
* 实现文件的复制操作
* @param srcFile 要复制的源文件
* @param descFile 要复制到的目标文件
*/
public static void copyFile(File srcFile,File descFile) throws Exception{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
//通过缓冲流去读
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(descFile));
byte[] bytes = new byte[1024*1024];
int num = 0 ;
while((num = bis.read(bytes)) != -1){
bos.write(bytes,0,num);
}
bos.flush();;
bos.close();
bis.close();
}
}
? ?
通过内部类的方式简化我们的线程的创建。
package com.bobo.thread;
public class ThreadDemo04 {
/**
* 如果我们创建的线程类 在程序中我们只需要创建一个线程就不需要再使用的情况下
* 我们可以通过内部类的方式来简化操作
* @param args
*/
public static void main(String[] args) {
Thread t1 = new Thread(){
@Override //重写run方法
public void run() {
System.out.println("子线程执行了...");
}
};
t1.start();
}
}
? ?
或者
package com.bobo.thread;
public class ThreadDemo05 {
/**
* 如果我们创建的线程类 在程序中我们只需要创建一个线程就不需要再使用的情况下
* 我们可以通过内部类的方式来简化操作
* @param args
*/
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
System.out.println("子线程执行了.......");
}
}.start();
}
}
??
2.第二种创建方式
在第一种实现方式中,我们是将线程的创建和线程执行的业务都封装在了
Thread
对象中,我们可以通过Runable
接口来实现线程程序代码和数据有效的分离。
Thread(Runnable target)
分配一个新的 Thread对象。
??
实现的步骤:
1.
创建
Runable
的实现类。
2.
重写
run
方法。
3.
创建
Runable
实例对象
(
通过实现类来实现
)。
4.
创建
Thread
对象,并把第三部的
Runable
实现作为
Thread
构造方法的参数。
5.
启动线程。
??
package com.bobo.runable;
public class RunableDemo01 {
/**
* 线程的第二种方式
* 本质是创建Thread对象的时候传递了一个Runable接口实现
* @param args
*/
public static void main(String[] args) {
System.out.println("main执行了...");
// 创建一个新的线程 Thread对象
Runnable r1 = new RunableTest();
//有别于第一种实现方式,通过Runable接口实现的线程可以多个线程同时操作一个Runable接口对象
Thread t1 = new Thread(r1);
// 启动线程
t1.start();
// 创建一个新的线程
System.out.println("main结束了...");
}
}
/**
* 线程的第二种创建方式
* 创建一个Runable接口的实现类
*/
class RunableTest implements Runnable{ //实现一个Runnable接口
@Override
public void run() {
System.out.println("子线程执行了...");
}
}
??
文章来源:https://blog.csdn.net/m0_52514893/article/details/134924417
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!