A程序:(简单使用)
一、继承Thread类创建线程类
- 重写run方法。该run()方法的方法体就代表了线程需要完成的任务。
- 创建Thread子类的实例。
- 调用线程对象的start()方法来启动该线程
package com.zwh.day01;
class MyThread extends Thread{//定义线程主题
private String name;
public MyThread(String name){//给线程设置一个线程名字
this.name=name;
}
@Override //重写run()方法,必须
public void run() {//线程运行的主方法
for (int x=0;x<5;x++){
System.out.println("【"+this.name+"】线程执行,当前的循环次数为 x="+x);
}
}
}
public class Demo {
public static void main(String[] args) {
MyThread myThreadA=new MyThread("A线程");
MyThread myThreadB=new MyThread("B线程");
MyThread myThreadC=new MyThread("C线程");
//1、错误启动线程
// myThreadA.run();
// myThreadB.run();
// myThreadC.run();
//正确启动线程
myThreadA.start();
myThreadB.start();
myThreadC.start();
}
}
结果:
【A线程】线程执行,当前的循环次数为 x=0
【C线程】线程执行,当前的循环次数为 x=0
【B线程】线程执行,当前的循环次数为 x=0
【C线程】线程执行,当前的循环次数为 x=1
【C线程】线程执行,当前的循环次数为 x=2
【A线程】线程执行,当前的循环次数为 x=1
【C线程】线程执行,当前的循环次数为 x=3
【C线程】线程执行,当前的循环次数为 x=4
【B线程】线程执行,当前的循环次数为 x=1
【B线程】线程执行,当前的循环次数为 x=2
【A线程】线程执行,当前的循环次数为 x=2
【A线程】线程执行,当前的循环次数为 x=3
【A线程】线程执行,当前的循环次数为 x=4
【B线程】线程执行,当前的循环次数为 x=3
【B线程】线程执行,当前的循环次数为 x=4
补充:(自己的源码笔记)
//jdk1.8-----Thread的start()源码,初学者可以跳过
public synchronized void start() {
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
private native void start0();//这个方法就是
JNI(Java Native Interface)----本地代码与 Java 虚拟机之间是通过 JNI 函数实现相互操作的
二、实现Runnable接口创建线程类
-
定义Runnable的实现类,重写run()方法。
-
创建Runnable实现类的实例,并以此作为Thread的target来创建对象,该对象才是真正的线程对象[解释在结果之后]。
package com.zwh.day01;
class MyThread implements Runnable{//定义线程主题
private String name;
public MyThread(String name){//给线程设置一个线程名字
this.name=name;
}
@Override //重写run()方法,必须
public void run() {//线程运行的主方法
for (int x=0;x<5;x++){
System.out.println("【"+this.name+"】线程执行,当前的循环次数为 x="+x);
}
}
}
public class Demo {
public static void main(String[] args) {
MyThread myThreadA=new MyThread("A线程");
MyThread myThreadB=new MyThread("B线程");
MyThread myThreadC=new MyThread("C线程");
new Thread(myThreadA).start();//启动线程并调用run()方法
new Thread(myThreadB).start();//启动线程并调用run()方法
new Thread(myThreadC).start();//启动线程并调用run()方法
}
}
结果:
【B线程】线程执行,当前的循环次数为 x=0
【C线程】线程执行,当前的循环次数为 x=0
【C线程】线程执行,当前的循环次数为 x=1
【C线程】线程执行,当前的循环次数为 x=2
【C线程】线程执行,当前的循环次数为 x=3
【C线程】线程执行,当前的循环次数为 x=4
【A线程】线程执行,当前的循环次数为 x=0
【B线程】线程执行,当前的循环次数为 x=1
【B线程】线程执行,当前的循环次数为 x=2
【B线程】线程执行,当前的循环次数为 x=3
【A线程】线程执行,当前的循环次数为 x=1
【A线程】线程执行,当前的循环次数为 x=2
【B线程】线程执行,当前的循环次数为 x=4
【A线程】线程执行,当前的循环次数为 x=3
【A线程】线程执行,当前的循环次数为 x=4
lamda表达式形式
package com.zwh.day01;
class MyThread implements Runnable{//定义线程主题
private String name;
public MyThread(String name){//给线程设置一个线程名字
this.name=name;
}
@Override //重写run()方法,必须
public void run() {//线程运行的主方法
for (int x=0;x<5;x++){
System.out.println("【"+this.name+"】线程执行,当前的循环次数为 x="+x);
}
}
}
public class Demo {
public static void main(String[] args) {
for(int x=0;x<3;x++){
String name=x+"线程对象";
new Thread(()->{
for (int i=0;i<5;i++){
System.out.println("["+name+"]线程执行,当前循环次数为"+i);
}
}).start();//启动线程并调用run()方法
}
}
}
结果:
[0线程对象]线程执行,当前循环次数为0
[0线程对象]线程执行,当前循环次数为1
[1线程对象]线程执行,当前循环次数为0
[1线程对象]线程执行,当前循环次数为1
[1线程对象]线程执行,当前循环次数为2
[1线程对象]线程执行,当前循环次数为3
[1线程对象]线程执行,当前循环次数为4
[2线程对象]线程执行,当前循环次数为0
[0线程对象]线程执行,当前循环次数为2
[0线程对象]线程执行,当前循环次数为3
[0线程对象]线程执行,当前循环次数为4
[2线程对象]线程执行,当前循环次数为1
[2线程对象]线程执行,当前循环次数为2
[2线程对象]线程执行,当前循环次数为3
[2线程对象]线程执行,当前循环次数为4
补充:
源码摘取
/* What will be run. */
private Runnable target;//Thread类的成员变量
public Thread(Runnable target) {//Thread类的构造方法,参数target
init(null, target, "Thread-" + nextThreadNum(), 0);
}
@Override
public void run() {
if (target != null) {
target.run();
}
}
Thread调用start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,
并没有运行,一旦得到cpu时间片,就开始执行run()方法,
这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,
此线程随即终止。此时的run()就是target的调用
三、使用Callable和Future创建线程
- 创建Callable接口的实现类,并实现Call()方法,该方法将作为线程执行体,且该方法有返回值,再创建Callable实现类的实例。从Java8开始,可以直接使用Lambda表达式创建Callable对象。
- 使用FutureTask来包装Callable对象,该FutureTask对象封装了该Callable对象的call方法的返回值。
- 使用FutureTask对象作为Thread对象的target创建并启动新线程。
- 调用FutureTask对象的get()方法来获取子线程执行结束后的返回值
package com.zwh.day01;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class MyThread implements Callable<String> {//定义线程主题
@Override
public String call() {
String result="";
for(int i=0;i<5;i++){
result+="学习多线程,我很开心"+i+"\n";
}
return result;
}
}
public class Demo {
public static void main(String[] args) throws Exception{
MyThread myThread = new MyThread();
FutureTask<String> futureTask=new FutureTask<>(myThread);
new Thread(futureTask).start();
System.out.println(futureTask.get());
}
}
结果:
学习多线程,我很开心0
学习多线程,我很开心1
学习多线程,我很开心2
学习多线程,我很开心3
学习多线程,我很开心4
扩展Callable撸源码,撸出的结构(借用借用,哈哈)
为啥会出现Callable?
//自己撸一撸
public class Thread extends Object implements Runnable
public interface Future<V>
public interface RunnableFuture<V> extends Runnable, Future<V>
public class FutureTask<V> extends Object implements RunnableFuture<V>{
FutureTask(Runnable runnable, V result);//补救,Runnable没有返回值
FutureTask(Callable<V> callable); //Callable
V get();//线程返回结果
}
public interface Callable<V>