多线程高并发编程】二 实现多线程的几种方式"/>
【多线程高并发编程】二 实现多线程的几种方式
程序猿学社的GitHub,欢迎Star
本文已记录到github,形成对应专题
文章目录
- 前言:
- 1.什么是多线程?
- 1.1应用场景
- 2.实现一个多线程的常见几种方式
- 通过继承的方式,实现多线程(第一种)
- 通过实现runnable接口,实现多线程(第二种)
- 匿名内部类实现(第三种)
- Runnable方式
- 继承类方式
- 通过Callable实现多线程(第四种)
- 启动一个main线程,启动了几个线程
- 多个线程进行测试
前言:
上章,我们已经了解线程的一些基本概念。本文我们来看看多线程的应用场景,为什么要用多线程,以及实现一个多线程有几种方式。
1.什么是多线程?
多线程是指通过软件优化和硬件(CPU)的方式,同时并发运行多个线程(任务)。更好的运行系统的资源。
例如,社长,很久以前,接到boss的提的一个业务,需要开发一个充电桩管理物联网管理平台,实现通过网站,查看各个充电桩的情况。如果就社长一个人开发,感觉1年搞定都有点难,毕竟社长专注于后端开发,这时社长就跟boss提出,需要增加人马,招一个前端,一个后端。社长就负责跟硬件对接,每个人负责一块,各种同步开发。最后,通过社长三人的努力,半年就交差了。这就是多线程的好处。多个人,信息也是共享(一个进程内的多个线程,资源是共享在同一个内存中)
1.1应用场景
- 网站发送多个请求,会一一返回结果,也就是很高的使用了多线程。如果没有多线程,我们抢票,就得发一个请求后,需要等请求处理完后,才能运行。
- 扣扣聊天界面,如果没有多线程,发一个消息,需要上一个消息处理完后,才能处理下一个需求。
- 通过netty解析数据报文,如果没有多线程,1w个线程,直接怼进来,我们只能一个个处理,肯定处理不过来,如果没有多线程,解析逻辑也无法和业务逻辑分离开,实现程序的解耦。
2.实现一个多线程的常见几种方式
为了模拟真实的场景,每个线程中,都增加了延迟运行的代码。
Thread.sleep(1000);
这句代码表示休眠1秒钟,以毫秒为单位。
通过继承的方式,实现多线程(第一种)
package com.cxyxs.two;import java.util.Date;/*** Description:第一种:通过继承的方式,实现多线程* 转发请注明来源 程序猿学社 - /* Author: 程序猿学社* Date: 2020/2/17 21:37* Modified By:*/
public class MyThreadExtend extends Thread {@Overridepublic void run() {for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("程序猿学社:社长在开发中,通过继承的方式实现:" + new Date());}}
}
调用代码
//第一种方式MyThreadExtend threadExtend = new MyThreadExtend();threadExtend.start();
- 因为java中是单继承,所以不推荐通过这种方式实现多线程。如果该类已经被继承,是无法继承Thread类的。
通过实现runnable接口,实现多线程(第二种)
package com.cxyxs.two;import java.util.Date;/*** Description:转发请注明来源 程序猿学社 - /* Author: 程序猿学社* Date: 2020/2/17 21:43* Modified By:*/
public class MyThreadRunnable implements Runnable{@Overridepublic void run() {for (int i = 0; i < 5; i++) {try {Thread.sleep(1200);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("小二在开发中,通过实现Runnable接口方式实现:" + new Date());}}
}
调用代码
//第二种方式
MyThreadRunnable runnable = new MyThreadRunnable();
Thread thread = new Thread(runnable);
thread.start();
匿名内部类实现(第三种)
Runnable方式
//匿名内部类-第一种new Thread(new Runnable() {@Overridepublic void run() {System.out.println("通过匿名内部类的方式第一种实现!");}}).start();
继承类方式
//匿名内部类-第二种new Thread(){@Overridepublic void run() {System.out.println("通过匿名内部类的方式第二种实现!");}}.start();
通过Callable实现多线程(第四种)
public class MyThreadCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int sum=0;for (int i = 0; i < 5; i++) {try {Thread.sleep(1500);} catch (InterruptedException e) {e.printStackTrace();}sum+=i;System.out.println("小王通过实现Callable接口的方式实现:" + new Date());}return sum;}
}
调用代码
//第四种 通过Callable实现多线程MyThreadCallable callable = new MyThreadCallable();FutureTask<Integer> result = new FutureTask<Integer>(callable);new Thread(result).start();try {Integer sum = result.get();System.out.println("计算结果:"+sum);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}
- 之前几种实现多线程的方法,需要重写run方法,启动多线程。而Callable方式实现多线程,需要重写call方法。通过FutureTask包装器来创建Thread线程
- 通过调用get方法获取多线程的运行结果。注意,get方法会一直堵塞,没有返回值,主线程会一直等待。
- 应用场景,例如批量大数据的导出,假设我们要导出100w数据,需要30s,我们就可以通过分页,每个线程查10w的数据,启动10个线程,来获取处理结果。这样就可以通过多线程提供查询的效率。
启动一个main线程,启动了几个线程
public class ThreadCount {public static void main(String[] args) {ThreadGroup group =Thread.currentThread().getThreadGroup();int count = group.activeCount();group.list();}
}
idea打印
eclipse打印
启动了2个线程,一个主线程main,是程序的入口。
还有一个[Monitor Ctrl-Break,这是IDEA特有的监控线程。正确的打印应该是gc线程。通过上面两张图,就可以得出这个结论。
多个线程进行测试
public class Test {public static void main(String[] args) {//第一种方式MyThreadExtend threadExtend = new MyThreadExtend();threadExtend.start();//第二种方式MyThreadRunnable runnable = new MyThreadRunnable();Thread thread = new Thread(runnable);thread.start();//第三种方式//匿名内部类-第一种new Thread(new Runnable() {@Overridepublic void run() {System.out.println("通过匿名内部类的方式第一种实现!");}}).start();//匿名内部类-第二种new Thread() {@Overridepublic void run() {System.out.println("通过匿名内部类的方式第二种实现!");}}.start();//第四种 通过Callable实现多线程MyThreadCallable callable = new MyThreadCallable();FutureTask<Integer> result = new FutureTask<Integer>(callable);new Thread(result).start();try {Integer sum = result.get();System.out.println("计算结果:"+sum);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}
}
- 通过测试的结果,我们发现,数据是交换运行的,如果是单cpu,每次只能运行一个通道,就算用多线程的方式实现,每次也是交替运行。只是计算机运行速度很快,我们看不出什么区别。说到这里,就有社友提出疑问,单cpu,还有必要用多线程吗?
就算是单cpu,利用多线程也有很多好处。让我们可以减少没必要的等待,更好的利用资源。 - 如果是多cpu,就可以同时并发运行多个任务,大大的提高运行效率。
更多推荐
【多线程高并发编程】二 实现多线程的几种方式
发布评论