前言:
今天给大家分享的java多线程的实现方式,估计一堆人,早已掌握,在这里也是再做一次回忆,加深一下印象。在上代码之前,我觉得不如分享下我是怎么学习多线程的。因为菜鸟一号表示当初学习的时候就被进程和线程搞得很烦。很烦咋办呢,我就先问度娘,她是这么说的
老实说,菜鸟就没看懂,越看越懵。看来度娘也不是万能的。那咋办呢,不急不急,动起你那勤快的小手,ctrl+alt+. 然后跳出这么个东西
看到哪个红色框框木有?
难道你是想说系统运行的exe程序,就能代表一个线程?没错!
通过查看任务服务管理器,我们可以将运行在内存中的exe文件,如图中的erl.exe文件理解成进程。而进程是受操作系统管理的基本运行单元。看到这里,是不是觉得,有点顿悟的感觉。
那么线程又是什么妖魔鬼怪呢?这玩意就很好理解了,当你打开英雄联盟.exe时他就有很多子任务也在同时运行,如开黑的语音线程,聊天窗口的线程,背景音乐线程,last but not least (放个洋屁)你正在操作的英雄的界面也是一个线程,这些不同的任务,或者说是功能都可以同时运行,其中每一项任务都可以理解为线程在工作,传输文件,发送消息。每一个功能都有对应的线程在后台默默执行。而多个线程同时工作,也就形成的多线程。就像你打撸啊撸时,就是多线程工作的完美体现。
多线程的特显就是在同一时间内可以执行多个任务,当然这也是多线程的优点。使用多线程其实就是在使用异步。
那么什么场景下需要使用多线程呢?
- 系统阻塞时。一旦系统阻塞,单线程就相当于宕机,我们需要使用多线程技术来提高运行效率。
- 当一个业务需要分两步A、B去完成时,如果A阻塞,B的执行不需要依赖于A的执行结果。那就可以使用多线程技术,提高运行效率。
注意!实际开发需要根据业务需求来确定使用单线程还是多线程,并不是说多线程就一定好于单线程。
我淦!晚上11点了,今天先分享这么多,下次分享多线程实现的几种方式!
----------------------------------------------2021/1/9 22点55分(sun)。
实现多线程的四个方式:(这里分享的都是多线程同步的案例)
1.继承Thread类然后重写run()方法;
public class MyThread extends Thread{
private int ticket = 5;
@Override
synchronized public void run() {
super.run();
ticket--;
System.out.println("当前线程"+this.currentThread().getName()+"操作"+ ticket);
}
}
public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 =new Thread(myThread,"A");
Thread t2 =new Thread(myThread,"B");
Thread t3 =new Thread(myThread,"C");
Thread t4 =new Thread(myThread,"D");
Thread t5 =new Thread(myThread,"E");
t1.start();//耗时
t2.start();
t3.start();
t4.start();
t5.start();
}
}
这是线程安全的案例,必须要使用synchronized关键字去保证线程安全,如果不加就会产生线程安全问题。
这里我列出不加上synchronized关键字运行的结果:
显然线程A和B输出的都是3,说明它两对3同时进行处理,就产生了线程安全问题。
2.实现Runnable接口重写Run()方法。
package com.sun.thread;
public class MyThreadRun implements Runnable{
private int ticket = 5;
@Override
synchronized public void run() {
ticket--;
System.out.println(Thread.currentThread().getName()+" "+ticket);
}
}
package com.sun.test;
import com.sun.thread.MyThreadRun;
public class TestRunable {
public static void main(String[] args) {
MyThreadRun myThreadRun = new MyThreadRun();
Thread t1= new Thread(myThreadRun);
Thread t2= new Thread(myThreadRun);
Thread t3= new Thread(myThreadRun);
Thread t4= new Thread(myThreadRun);
Thread t5= new Thread(myThreadRun);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
3.实现callable接口重写run方法:它有返回值,runnable没有。
package com.sun.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
/**
* Runnable接口:重写run() run()方法里面写的是线程执行的业务逻辑。
* run()方法没有返回值,无法获取到线程执行的结果。
* Callable接口:重写call() call()方法里面写的也是线程执行的业务逻辑。
* call()方法有返回值,可以获取到每个线程执行的结果。
* @author Administrator
*<P>Title:MyThreadCall</p>
*<P>Description: </p>
* @author svv
*/
public class MyThreadCall implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("我执行了"+Thread.currentThread().getName());
return "ZXZXZX";
}
public static void main(String[] args) throws Exception {
Callable<String> callable = new MyThreadCall();
//FutureTask对象是用来接受异步执行的结果
FutureTask<String> futureTask1 = new FutureTask<>(callable);
FutureTask<String> futureTask2 = new FutureTask<>(callable);
FutureTask<String> futureTask3 = new FutureTask<>(callable);
FutureTask<String> futureTask4 = new FutureTask<>(callable);
Thread thread = new Thread(futureTask1);
Thread thread1 = new Thread(futureTask2);
Thread thread2 = new Thread(futureTask3);
Thread thread3 = new Thread(futureTask4);
thread.start();
thread1.start();
thread2.start();
thread3.start();
System.out.println(futureTask1.get());
System.out.println(futureTask1.get());
System.out.println(futureTask1.get());
System.out.println(futureTask1.get());
}
}
4.基于Callable接口,利用Java的线程池来实现多线程.。推荐,好处就是多路复用(高效利用每一线程,提高线程的利用率。应用程序的执行效率和速度也随之提高。)
package com.sun.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadPool implements Callable<String>{
@Override
public String call() throws Exception {
return "当前线程"+Thread.currentThread().getName();
}
public static void main(String[] args) throws Exception{
//创建初始化线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
for(int i = 0;i<10;i++){
//创建资源访问对象
ThreadPool threadPool = new ThreadPool();
//提交资源任务
Future<String> submit = executorService.submit(threadPool);
System.out.println(submit.get());
}
//关闭线程池
executorService.shutdown();
}
}
Executors类:提供了一系列工厂方法用于创建线程池,返回的线程池都实现了ExecutorService接口。
- public static ExecutorService newFixedThreadPool(int nThreads)
创建固定数目线程的线程池。 - public static ExecutorService newCachedThreadPool()
创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
3.public static ExecutorService newSingleThreadExecutor()
创建一个单线程化的Executor。 - public static ScheduledExecutorService
newScheduledThreadPool(int corePoolSize)
创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。