免费永久不限空间,wordpress中文网站优化,做网站好多钱,做最简单的网站目录
1. 线程的概念
2. 创建与使用多线程
2.1 方式1#xff1a;继承Thread类
2.2 方式2#xff1a; 实现Runnable接口
2.3 以上两种创建线程方式的对比
3. 多线程的优势-增加运行速度 1. 线程的概念
进程的存在是由于系统的多任务执行需求#xff0c;这也要求程序员进…目录
1. 线程的概念
2. 创建与使用多线程
2.1 方式1继承Thread类
2.2 方式2 实现Runnable接口
2.3 以上两种创建线程方式的对比
3. 多线程的优势-增加运行速度 1. 线程的概念
进程的存在是由于系统的多任务执行需求这也要求程序员进行并发编程
使用多进程是完全可以实现并发编程的但如果要频繁地创建或销毁如分配、销毁内存或文件以及频繁地调度进程资源的申请和释放不仅低效成本也非常高
为了解决这个问题通常会通过两个方式
1进程池效率有一定提高但进程池中的闲置进程不使用的时候仍然在消耗系统资源故而使用进程池的系统资源消耗是非常大的
2线程线程比进程更轻量每个线程也能够执行一个任务代码也能够并发编程
创建、调度、销毁一个线程的成本相比进程而言要低很多在Linux上也把线程称为轻量级进程
进程重量重在资源的申请和释放线程则是包含在进程中的一个进程中的多个线程共用同一份资源同一份内存文件只有在创建进程的第一个线程时由于需要分配资源成本是相对较高对的后续在这个进程中再创建其他线程的成本都比较低
但是并非线程越多越好如果线程过多就会存在资源竞争导致速度受限
注进程与线程的区别与联系
1进程包含线程一个进程里可以包含一个线程也可以包含多个线程
2进程和线程都是为了处理并发编程场景但进程频繁创建、调度、释放时效率较低消耗较大而线程由于少了申请释放资源的过程故而更轻量创建、调度、释放都效率更高消耗更少
3操作系统创建进程需要给进程分配资源故而进程是操作系统分配资源的基本单位
操作系统创建线程是要在CPU上调度执行故而线程是操作系统调度执行的基本单位
4进程具有独立性每个进程都由各自的虚拟地址空间进程之间互不影响
同一个进程中的多个线程共用同一个内存空间线程之间可能会互相影响
2. 创建与使用多线程
2.1 方式1继承Thread类
java标准库提供了一个Thread类来表示、操作线程Thread类也可视为是java标准库提供的API
创建好的Thread实例和操作系统中的线程是一一对应的关系
操作系统提供了一组关于APIC语言java对于这组API进一步封装形成了Thread类
示例代码1单线程创建示例
class MyThread extends Thread{Overridepublic void run(){System.out.println(Hello Thread.);}
}
public class Demo1 {public static void main(String[] args) {Thread t new MyThread();t.start();}
}
注1通过Thread类创建线程有很多种写法最简单的就是创建子类继承Thread并且重写run方法
2run方法中描述该线程要执行哪些代码由于每个线程都是并发执行的因此需要告知每个线程要执行的代码内容run方法中的逻辑是在新创建出的线程中被执行的代码
3start方法的调用代表着在系统中真正创建了线程此时才开始执行上文的run操作
4这里创建线程是在同一个进程中创建的
5线程之间是并发进行的
6线程强制中断异常是多线程中最常遇到的异常之一 7Thread是java.lang中的类是不需要导入包的类似的还有String也是不需要导入的 示例代码2多线程创建示例
class MyThread extends Thread{Overridepublic void run(){while(true){System.out.println(Hello Thread);try {Thread.sleep(1000);//休眠强制使线程进入阻塞状态 单位为ms//即1s内这个线程不会到cpu上执行}catch(InterruptedException e){e.printStackTrace();}}}
}
public class Demo1 {public static void main(String[] args) {Thread t new MyThread();t.start();while(true){System.out.println(Hello Main);try {Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}}}
}
截取部分输出结果如下 注1一个进程中至少会有一个线程在一个java进程中也至少会有一个调用main方法的线程只是该线程是系统自动生成的而非手动创建的此时我们手动创建的t线程与自动创建的main线程就是并发执行的关系这两个线程从宏观上看该输出结果就是同时执行的
2两个线程都是打印一条语句后休眠1s当1s结束后系统先唤醒哪个线程是随机的即对于操作系统来说内部对线程之间的调度顺序在宏观上也可以认为是随机的这种调度方式也称为抢占式执行
3sleep是一个毫秒级休眠语句并没有那么精确比如sleep(1000)的含义是1000ms之内不能上CPU而不是1000ms之后准时上CPU故而结束阻塞状态的具体时间是不确定的这与线程之间的调度是随机的也是彼此互相印证的
4start方法用于启动线程
示例代码3使用匿名内部类
public class Demo3 {public static void main(String[] args) {//1.创建一个匿名内部类继承自Thread类//2.重写run方法//3.new这个匿名内部类的实例Thread t new Thread(){public void run(){System.out.println(Hello Thread.);}};t.start();}
}
2.2 方式2 实现Runnable接口
创建一个类实现Runnable接口再创建Runnable实例传给Thread实例
代码示例1实现Runnable接口创建线程
//Runnable 就是在描述一个任务
class MyRunnable implements Runnable{Overridepublic void run(){System.out.println(Hello);}
}
public class Demo2 {public static void main(String[] args) {Thread t new Thread(new MyRunnable());t.start();}
}
通过Runnable来描述任务的内容进一步地再把描述好的任务交给Thread实例
代码示例2使用匿名内部类
public class Demo4 {public static void main(String[] args) {//1.new Runnable的匿名内部类//2.将new的Runnable实例传给Thread的构造方法Thread t new Thread(new Runnable(){public void run(){System.out.println(Hello Thread.);}});t.start();}
}
需要将new 的Runnable的实例传递给Thread故而需要包含其重写的run方法
代码示例3使用lambda表达式
public class Demo5 {public static void main(String[] args) {Thread t new Thread(()-{System.out.println(Hello Thread.);});t.start();}
}
lambda表达式就是一个匿名方法()表示方法参数-表示是一个lambda{}中编写方法内容
2.3 以上两种创建线程方式的对比
通常认为Runnable方式会更好一点能够做到让线程与线程执行的任务更好地进行解耦
编写代码通常希望高内聚、低耦合。
Runnable只是描述了一个任务但是任务的执行方式是进程、线程、线程池还是协程来执行Runnable内部并不作涉及Runnable内部的代码也不涉及
3. 多线程的优势-增加运行速度
多线程编程的优势显著体现在可以提高任务完成的效率
如现有两个整数变量分别对这两个变量自增10亿次分别使用一个线程与两个线程进行演示
public class Demo6 {private static final long count 10_0000_0000;public static void serial(){ //串型执行//记录程序执行时间long beg System.currentTimeMillis();long a 0;for(long i0;icount;i){a;}long b 0;for(long i0;icount;i){b;}long end System.currentTimeMillis();System.out.println(Single Thread Time: (end-beg) ms.);}public static void concurrency() throws InterruptedException {long beg System.currentTimeMillis();Thread t1 new Thread(()-{long a 0;for(int i0;icount;i){a;}});t1.start();Thread t2 new Thread(()-{long b 0;for(int i0;icount;i){b;}});t2.start();//不能在此处直接记录结束时间该方法是在main线程中执行的//main线程与t1、t2线程是并发执行的即t1、t2尚未执行结束此时就已经记录结束时间了//应将main线程等待t1与t2线程执行完毕再进行计时t1.join();t2.join();//join方法效果就是等待线程结束哪个线程调用则令main线程等待哪个线程结束long end System.currentTimeMillis();System.out.println(Multi Thread Time: (end-beg) ms.);}public static void main(String[] args) throws InterruptedException {serial();concurrency();}
}输出结果为 注1增加线程并非一定会达到翻倍的速度提升因为两个线程在底层到底是并行执行还是并发执行并不确定 底层微观真正并行执行的时候效率才会有显著提升
2当count不够大时反而可能会导致程序执行速度更慢因为创建线程本身也需要时间开销此时代码的执行时间反而更多地消耗在了创建线程上
3多线程适合应用于CPU密集型的程序当程序需要进行大量的计算时使用多线程就可以更充分地利用CPU的多核资源