多线程的实现方式
一、继承Thread类
(一)步骤
- 写一个继承Thread类的子类A
- 重写run方法
- 方法体即为线程体,是线程要实现的功能
- 实例化A类的对象
- 调用start()启动线程
(二)线程名称
1、不设置线程名称
系统默认设置
2、设置线程名称
方法一 使用方法setName()
在实例化子类对象后,用对象调用方法setName()
方法二 使用构造方法
在写继承Thread的子类时,写出构造方法
(三)代码
//1、写一个继承Thread类的子类A
public class A extends Thread{
//2、重写run方法
@Override
public void run(){
//线程体
for(int i=1 ; i<=100 ; i++){
// String getName()返回此线程的名称
System.out.println(getName()+":"+i);
}
}
//设置线程名称 方法二 构造方法
public A(){}
public A(String name){
super(name);
}
}
public class Demo{
public static void main(String[] args){
//3、实例化A类的对象
/* //设置线程名称 方法一 使用方法setName()
A a1 = new A();
A a2 = new A();
a1.setName("沈巍");
a2.setName("面面");
*/
A a1 = new A("卡厄斯");
A a2 = new A("泰坦");
//4、调用start()启动线程
a1.start();
a2.start();
}
}
二、实现Runnable接口
(一)步骤
- 写一个实现Runnable接口的实现类B
- 重写run()方法
- 实例化B对象
- 实例化线程对象,传入B对象
- 调用start()启动线程
(二)线程名称
- 设置线程名称
- 设置 Thread 的构造方法
- setName()
- 获取线程名称
- Thread.CurrentThread.getName
(三)代码
//1、一个实现Runnable接口的实现类
public class B implements Runnable{
//2、重写run()方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
//3、再写一个类,实例化B
package cn.jing.process.runnable_;
public class MyRunnableDemo {
public static void main(String[] args) {
//3、实例化实现接口类的对象
B m = new B();
/*
* 创建对象设置名字的方法有两个
* */
//一 、创建thread 对象 ,将实现类对象作为构造方法的参数传递
Thread t1 = new Thread(m);
Thread t2 = new Thread(m);
//setName()设置名称
t1.setName("沈");
t2.setName("赵");
//二、 创建Thread 对象时,即在构造方法里将名字设置好
Thread t3 = new Thread(m,"朱");
Thread t4 = new Thread(m,"白");
/*
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}*/
//5、启动线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
三、实现Callable接口
//1、创建一个实现Callable的实现类
//2、实现call方法,call方法可以有返回值,不想要返回null
class Num implements Callable{
@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;
}
}
package cn.dxc_achieve.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
// 输出偶数 和 偶数和
public class Demo_Callable {
public static void main(String[] args) {
// 3、创建Callable接口实现类的对象
Num num = new Num();
// 4、将对象作为参数传递给FutureTask构造方法,创建对象
FutureTask task = new FutureTask(num);
//将FutureTask的对象作为参数传给thread的构造器,创建对象,调用start()
new Thread(task).start();
try {
// 6、如果想要,可以获取callable方法的返回值
// get()方法的返回值即为 futureTask构造器参数Callable实现类重写的call()的返回值
Object sum = task.get();
System.out.println("总和为:"+sum);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
四、线程池
程序启动一个新线程成本较高,使用线程池可以提高性能【尤其是程序中要创建大量生存期很短的线程时】
(一)概述
线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池
(二)Executors工厂类
•JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
Executors工厂类的方法 | 功能 |
---|---|
public static ExecutorService — | 返回值是ExecutorService对象 |
newCachedThreadPool() | 创建一个具有缓存功能的线程池 |
newFixedThreadPool(int nThreads) | 创建一个可重用的,具有固定线程数的线程池 |
newSingleThreadExecutor() | 创建一个只有单线程的线程池 |
这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
ExecutorService 方法 | 功能 |
---|---|
Future<?> submit(Runnable task) | 执行Runnable对象 |
Future submit(Callable task) | 执行Callable对象 |
void shutdown | 关闭线程池 |
(三)实现步骤
线程池执行Runnable对象
- 创建线程池对象
- 创建Runnable实例
- 提交Runnable实例
- 关闭线程池
//一个实现Runnable接口的实现类
public class B implements Runnable{
//重写run()方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
//线程池执行Runnable对象
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyRunnableDemo {
public static void main(String[] args) {
//创建线程池对象
ExecutorService pool = Executors.newFixedThreadPool(2);
//实例化Runnable,并提交
pool.submit(new B());
pool.submit(new B());
//关闭线程池
pool.shutdown();
}
}