什么是线程?
线程(Thread)是一个程序内部的一条执行语句。
程序如果只有一条执行流程,那这个程序就是单线程程序。
多线程是什么?
多线程是从软硬件是指从软硬件上实现的多条执行流程图技术(多条线程由CPU调度执行)。
如何在程序中创建出多条线程?
java是通过java.lang.Thread类的对象来代表线程。
方式一:
声明为Thread的子类,此子类覆盖类Thread的run方法。
public class MyThread extends Thread{
//重写run方法
@Override
public void run(){
//描述线程的执行任务
for(int i=0;i<5;i++){
System.out.println("线程输出"+i);
}
}
}
public class Test{
public static void main(String[] args){
//main方法是由一类默认的主线程负责执行。
//创建MyTread线程类的对象
Thread t=new MyThread();
//启动线程(自动执行run方法)
t.strat();
for(int i=1;i<5;i++){
System.out.println("主线程"+i);
}
}
}
说明:
每次执行情况随机
方式一优缺点:
优点:编码简单
缺点:线程类已经继承Thread,无法继承其他类,不利于功能拓展。
多线程的注意事项:
1.启动线程必须是调用start方法,不是调用run方法
public class Test{
public static void main(String[] args){
//main方法是由一类默认的主线程负责执行。 //创建MyTread线程类的对象
Thread t=new MyThread();
//执行run方法
t.run();
for(int i=1;i<5;i++){ System.out.println("主线程"+i);
}
}
}
说明:
相当于调用run方法,是单线程,没有实现多线程
2.不要把主线程任务放在子线程之前
会使主线程都执行完
方式二:实现runnable接口
声明一个实现runnable接口的类,该类实现run方法,然后可以分配类的实例,然后启动。
//定义一个任务类,实现Runnable接口
public class MyRunnable implement Runable{
//重写runnable的run方法
@Override
public void run(){
//描述线程的执行任务
for(int i=0;i<=5;i++){System.out.println("线程输出"+i);}
}
}
public class Test2{
public static void main(String[] args){
//main方法是由一类默认的主线程负责执行。
//创建任务对象
Runable target=new MyRunnable();
//把任务对象交给一个线程对象
//public Thread(Runnable target)
//启动线程(自动执行run方法)
new Thread(target).strat();
for(int i=1;i<=5;i++){
System.out.println("主线程"+i);}
}
}
说明:start是线程对象独有的,需要把任务对象交给线程对象启动。
方法二优缺点:
优点:任务类是实现接口,可以继承其他类,实现其他接口,扩展性强。
线程创建方式二的匿名内部类写法
public class Test3{
public static void main(String[] args){
//main方法是由一类默认的主线程负责执行。
//创建Runnable接口的匿名内部类(任务对象)
Runable target=new Runnable(){
@Override
public void run(){
for(int i=1;i<=5;i++)
{
System.out.println("子线程"+i);
}
}
};
//启动线程(自动执行run方法)
new Thread(target).strat();
for(int i=1;i<=5;1++){
System.out.println("主线程"+i);}
}
}
简化方式1:
new Thread(new Runnable(){
@Override
public void run(){
for(int i=1;i<=5;i++){ System.out.println("子线程"+i);
}
}
}).start();
简化方式2:
new Thread(()->{
for(int i=1;i<=5;i++){ System.out.println("子线程"+i);
}
} ).start();
前两种线程创建方式都存在一个问题
run方法不能直接返回结果。
方式三:利用Callable接口和FutureTask类
//定义一个任务类,实现Callable接口
public class MyCallable implement Callable<String>{
private int n;
public MyCallable(int n){
this.n=n;
}
//重写Callable的call方法
@Override
public String call() throwException{
//描述线程的任务就是返回线程执行返回的结果
int sum=0;
for(int i=0;i<=n;i++){
sum+=i;
}
return sum;
}}
public class Test4{
public static void main(String[] args) throws Exception{
//main方法是由一类默认的主线程负责执行。
//创建Callable的对象
Callable<String> call=new MyCallable(100);
//把Callable对象封装成一个Futureable对象(任务对象)
FutureTask<String> f1=new Futrureable<>(call);
//作用:
//是一个任务对象,实现了Runnable接口
//可以在线程执行完毕后,用get方法获取结果
//把任务对象交给一个线程对象
//启动线程(自动执行call方法)
new Thread(f1).strat();
// 获取线程执行完毕的结果
//如果执行到这里上面线程没有执行完,主线程会暂停获取结果
String rs= f1.get();
System.out.println(rs);
for(int i=1;i<=5;i++){ System.out.println("主线程"+i);
}
}
}
方式三:
优点:
线程任务类只是实现接口。可以继承类和实现接口,扩展性强,可以在线程执行完毕后获取线程执行的结果。
缺点:编码相对复杂。