这几天在学习Java多线程,今天做一个总结
Java创建多线程的方式有四种,接下来就逐个介绍:
1.继承Thread类的方式
2.实现Runnable接口的方式
3.实现Callable接口的方式
4.使用线程池
1.创建多线程方式一:继承Thread类的方式创建多线程
1.1主要步骤:
- 创建继承Thread类的子类
- 在继承Thread类的子类中重写run()方法
- 将此线程要做的操作写在run()方法中
- 创建继承Thread的子类的对象
- 使用
对象.start();
的方式启动多线程
注意:
1.一个线程只能start()一次,要想创建多个线程,就需要创建多个Thread子类对象,进行调用start()方法
2.不能调用run()方法启动线程
3.这里的start()方法有两个作用:使用线程开始执行;JVM调用run()方法
1.2Thread常用方法:
- start():启动当前线程;调用当前线程的run()方法
- run():通常需要重写thread类中的run()方法,将创建的线程要执行的操作声明在此方法中
- currentThread():是静态方法,返回当前代码执行的线程
- getName():获取当前线程的名字
- setName():设置当前线程的名字
- yield():释放当前CPU的执行权
- join():在线程A中调用线程B的join()方法,此时线程A就会进入阻塞状态,直到线程B结束运行,线程A才执行
- sleep(int millisecond):让当前线程睡眠指定的毫秒数,在指定的之间内,当前线程是阻塞状态
- getPriority():获取当前线程的优先级
- setPriority(int p):设置当前线程的优先级
//1.创建一个继承于Thread类的子类
class MyThread extends Thread {
// 2.重写Thread的run()方法-->将此线程执行的操作声明在run()中
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(i % 2 == 0){
System.out.println(i);
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
//3.创建Thread子类的对象
MyThread myThread = new MyThread();
//4.通过子类对象调用start()方法;
//作用1:使此线程开始执行
//作用2:Java虚拟机调用此线程的run()方法
myThread.start();
MyThread myThread1 = new MyThread();
myThread.start();
}
}
2.创建多线程方式二:实现Runnable接口的方式创建多线程
2.1主要步骤:
- 创建实现Runnable接口的实现类
- 在实现Runnable接口的实现类中重写run()方法
- 将此线程要做的操作写在run()方法中
- 创建实现类的对象
- 将实现类的对象以参数的方式传递到Thread类的构造器中,创建Thread类的对象
- 使用
Thread对象.start();
的方式启动多线程
注意:
1.如果创建多个线程的话,就将Runnable实现类的对象给Thread构造器,创建Thread类的对象,然后调用start()
2.在平时,对比上一种方式,使用实现Runnable接口的方式创建多线程的好处更多:不用考虑单继承性;实现的方法更有利于共享资源的使用
3.Thread也实现了Runnable接口
//1.创建一个实现了Runnable接口的类
class MThread implements Runnable{
//2.实现类去实现Runnable中的run()方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
}
public class ThreadTest1 {
public static void main(String[] args) {
//3.创建实现类的对象
MThread p = new MThread();
//4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
Thread mythread = new Thread(p);
//5.通过Thread类的对象调用start()方法:
//作用1:启动线程
//作用2:调用当前线程的run()方法-->调用了Runnable类型的target的run()
mythread.start();
//再启动一个线程,遍历100以内的偶数
Thread mythread2 = new Thread(p,"新线程@");
mythread2.start();
}
}
3.创建多线程方式三:实现Callable接口的方式创建多线程
3.1主要步骤:
- 创建Callable接口的实现类
- 在实现类中重写call()方法
- 将此线程要做的操作写在call()方法中
- 创建实现类的对象
- 将实现类的对象以参数的方式传递给FutureTask类的构造器中,创建FutureTask类的对象
- 将FutureTask类的对象以参数的方式传递给Thread类的构造器中,创建Thread类的对象
- 使用
Thread对象.start();
的方式启动多线程 - 可以使用
FutureTask类的对象.get()
的方式获取call()方法的返回值
注意:
1.call()方法有返回值,而run方法没有返回值,call()返回值的类型为Object,接收时必须强转
2.使用FutureTask类的对象.get()
的方式获取call()方法的返回值,get(方法)需要异常捕获
//1.创建一个实现Callable的实现类
class NumThread implements Callable {
//2.实现Call()方法,将此线程需要执行的操作声明在call()中,Call()方法有返回值
@Override
public Object call() throws Exception {
int sum = 0;
for (int i = 0; i < 100; i++) {
if (i % 2 == 0){
System.out.println(i);
sum += i;
}
}
return sum;
}
}
public class ThreadNew {
public static void main(String[] args) {
//3.创建Callable实现类的对象
NumThread numThread = new NumThread();
//4.将此Callable接口实现类的对象作为参数传递到FutureTask构造器中,创建FutureTast的对象
FutureTask futureTask = new FutureTask(numThread);
//5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread类的对象
Thread thread = new Thread(futureTask);
//6.调用Thread类的start()方法
thread.start();
//7.获取Callable中的call()方法的返回值
try {
//get()返回值即为FutureTask构造器参数Callable实现类重写的call()返回值
Object sum = futureTask.get();
System.out.println("总和为:"+sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
4.创建多线程方式三:创建线程池的方式创建多线程
4.1主要步骤:
- 通过实现Runnable接口的方式或实现Runnable接口的方式创建一个实现类
- 在实现类中重写run()或call()方法
- 将线程要做的操作写在call()方法或run()中
- 创建实现类的对象
- 创建线程池
//创建多类线程池:
ExecutorService service = Executors.newFixedThreadPool(int nThreads);
//创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
ExecutorService service = Executors.newCachedThreadPool();
//创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
ExecutorService service = Executors.newScheduledThreadPool(int corePoolSize);
//创建一个定长线程池,支持定时及周期性任务执行。
ExecutorService service = Executors.newSingleThreadExecutor();
//创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
- 使用
线程池.execute(实现类的对象)
的方式执行
//1.通过实现Runnable接口的方式或实现Runnable接口的方式创建一个实现类
class NumberThread implements Runnable{
//2.在实现类中重写run()或call()方法
@Override
public void run() {
//3.将线程要做的操作 写在call()方法或run()中
for (int i = 0; i < 100; i++) {
if(i % 2 == 0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
public class Threadpool {
public static void main(String[] args) {
//4.创建实现类的对象
NumberThread myThread = new NumberThread();
//5.提供指定数目的线程池
ExecutorService service =Executors.newFixedThreadPool(10);
//6.执行指定的线程操作。需要提供实现Runnable接口实现类的对象
service.execute(myThread);
}
}
使用线程池好处:
- 1.提高响应速度(减少了创建线程的时间)
- 2.降低资源消耗(重复使用线程池中的线程,不需要每次都创建)
- 3.便于线程管理