Java创建多线程
Java语言的JVM允许程序运行多个线程,它通过java.lang.Thread类来体现。
Thread类的特性
每个线程都是通过某个特定Thread对象的run()方法来完成操作的,经常把run()方法的主体称为线程体
通过该Thread对象的start()方法来启动这个线程,而非直接调用run()
创建多线程的四种方式
java中创建多线程的四种方式,分别是继承Thread类,实现Runnable接口,jdk5.0以后又增加了两种方式:实现Callable接口和使用线程池。
继承Thread类
步骤
1、定义一个类继承Thread类
2、重写run方法,里面写线程要执行的任务代码
3、创建Thread子类对象
4、调用start方法,开启线程并调用run方法
举个例子
遍历输出100以内的所有偶数
//1、定义一个类继承Thread类
class Mythread extends Thread{
//2、重写run方法,里面写线程要执行的任务代码
@Override
public void run() {
for(int i=0;i<100;i++){
if(i%2==0){
System.out.println(i);
}
}
}
}
public class test1 {
public static void main(String[] args) {
//3、创建Thread子类对象
Mythread t1=new Mythread();
//4、调用start方法,开启线程并调用run方法
t1.start();
}
}
实现Runnable接口
步骤
1、创建一个实现Runnable接口的子类
2、子类中重写run方法,写任务代码
3、创建实现子类的对象
4、通过Thread类创建线程对象,并将该子类对象作为构造器的参数进行传递
5、调用Thread类的start方法
举个例子
创建三个窗口卖票,总票数为100张
/*
创建三个窗口卖票,总票数为100张,使用实现Runnable接口方式
存在线程的安全问题,后面解决
*/
//1、创建一个实现Runnable接口的子类
class Window implements Runnable{
private int ticket=100;
//2、子类中重写run方法,写任务代码
@Override
public void run() {
while(true){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+ticket);
ticket--;
}else{
break;
}
}
}
}
public class Tickets {
public static void main(String[] args) {
//3、创建子类的对象
Window w=new Window();
//4、通过Thread类创建线程对象,并将该子类对象作为构造器的参数进行传递
Thread w1=new Thread(w);
Thread w2=new Thread(w);
Thread w3=new Thread(w);
w1.setName("窗口1");
w2.setName("窗口2");
w3.setName("窗口3");
//5、调用Thread类的start方法
w1.start();
w2.start();
w3.start();
}
}
线程安全问题解决措施:
https://blog.csdn.net/qq_41117896/article/details/109473648
实现Callable接口
步骤
- 创建Callable的实现类:class XxxXxx implements Callable
- 重写call方法,将线程的任务代码封装到call方法中:public Object call() throws Exception{}
- 创建Callable接口实现子类的对象;
- 创建FutureTask的对象,将此Callable接口实现类的对象作为构造器的参数进行传递: FutureTask futureTask = new FutureTask(numThread);
- 创建Thread对象,并调用start()。将FutureTask的对象作为参数传递到Thread类的构造器中:new Thread(futureTask).start();
- 获取Callable中call方法的返回值。 get() 返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值
举个例子
输出100以内偶数的和
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
//1、创建Callable的实现类
class Mythread3 implements Callable{
//2、重写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 test3 {
public static void main(String[] args) {
//创建Callable接口实现子类的对象
Mythread3 t3=new Mythread3();
//创建FutureTask的对象,将此Callable接口实现类的对象作为构造器的参数进行传递
FutureTask ft=new FutureTask(t3);
//创建Thread对象,并调用start()
new Thread(ft).start();
try{
//获取Callable中call方法的返回值。 get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值
Object sum=ft.get();
System.out.println("总和是:"+sum);
}catch (InterruptedException | ExecutionException e){
e.printStackTrace();
}
}
}
使用线程池
步骤
- 提供指定线程数量的线程池;借助于Executors中的方法;
- 执行指定的线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象
- Runnable:service.execute(子类对象)
- Callable:service.submit(子类对象)
- 关闭连接池
举个例子
输出100以内奇数的和
import java.util.concurrent.*;
class MythreadCall implements Callable{
@Override
public Object call() throws Exception {
int sum=0;
for(int i=0;i<100;i++){
if(i%2!=0){
sum+=i;
}
}
return sum;
}
}
public class test4 {
public static void main(String[] args) {
//1、提供指定线程数量的线程池;借助于Executors中的方法;
ExecutorService service = Executors.newFixedThreadPool(10);
//2、执行指定的线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象
Future future=service.submit(new MythreadCall());
try {
System.out.println("输出结果"+future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//3、关闭连接池
service.shutdown();
}
}