Thread t=Thread.currentThread();//引用当前正在运行的线程,意义何在?
两大主要方式的框架
① 直接继承 Thread 类
② 实现 Runnable 接口,把对象放在 Thread 对象中。
- 构造线程方式一:直接继承Thread类
线程必须先new,再start(),注意:
(1)start()源自Thread类,start()不能被重写、一个线程不能多次start()、
(2)线程start(),不等同于线程立即能够执行,仅仅表示线程“具备执行的条件”,
至于何时执行,有JVM决定;
(3)main是守护线程,只有当main中直接或间接产生的所有线程都结束,main才会结束
换言之,由于main是程序的入口,故main实际上是最后结束的线程。
需求:线程中有变量int型data,让data+2重复50次
效果:若data是1,则输出1、3、5、7、……51;
若data是2,则输出2、4、6、8、……52;
class Thread_A extends Thread{
private int data;
private String name;
public Thread_A(int x, String s) { data=x; name=s;}
public void run() {//注:这里就是线程对应的代码段
//注:作为线程的run,必须用publi void ,且无参
// 因为这个run,实际上就是重写 Runnable接口中的run
//注意:Thread类也重写了Runnable接口
System.out.print(name+"开始:\n");
for(int i=0; i<50; i++) {data=data+2;
System.out.print(data+" ");
}
System.out.print(name+"结束.\n");
}
}
class App1{
public static void main(String[] args) {
System.out.print("main开始 ");
Thread_A a=new Thread_A(1,"奇数线程"); //创建线程,但未启动
Thread_A b=new Thread_A(2,"偶数数线程");
a.start(); b.start();//启动线程,开启线程声明周期,即线程开始执行
System.out.print("main结束 ");
}
}
- 构造线程的方式二:
(1)让类Thread_B实现Runnable接口(当然必须实现接口中的run方法)
(2)构造Thread_B的对象,并将该对象填入Thread的构造器中
如,希望“开车郊游”,类比:
方式一:自己有车、自己开
方式二:自己会驾驶(即有run()), 但开别人的车(即另造一个Thread)
这种方式的好处:不影响类的继承(注:java是单继承)
Thread_B的对象不是线程,仅仅具备线程体(即Runnable中的run())
实现线程必须要有Thread类
class Thread_B implements Runnable{
private int data; private String name;
Thread_B(int x, String s){ data=x; name=s; }
public void run(){
System.out.print(name+"开始 ");
if(data<=0)return;
int i=1;
while(i*data<50) {
System.out.print(i*data+" "); i++;
}
System.out.print(name+"结束.\n ");
}
}
public class BuildThread2 {
public static void main(String[] args) {
System.out.print("main开始 ");
Thread_B t2=new Thread_B(2,"二线程 ");
Thread_B t3=new Thread_B(3,"三线程 ");
Thread_B t5=new Thread_B(5,"五线程 ");
//注意:t2、t3、t5不是线程对象
Thread t22=new Thread(t2);//t22才是线程对象
Thread t33=new Thread(t3);//t33才是线程对象
Thread t55=new Thread(t5);//t55才是线程对象
//注意:上述仅仅构造出线程对象,尚未启动
t22.start();t33.start();t55.start();
System.out.print("main结束.\n "); }
}
直接造Thread_C的对象,并 start() ,即伪造start()
class Thread_C implements Runnable{
private int data;
private Thread t; //不可少,用于
Thread_C(int x, String s){
data=x;
t=new Thread(this); //此句作用: 先造Runnable的实现对象,再将该对象填入Thread对象中
t.setName(s);
}
public void start() {t.start(); }//伪造的start()
public void run(){
System.out.print(t.getName()+"开始 ");
if(data<=0)return;
int i=1;
while(i*data<50) {
System.out.print(i*data+" "); i++;
}
System.out.print(t.getName()+"结束.\n ");
}
}
class App3{
public static void main(String[] args) {
System.out.print("main开始 ");
Thread_C t2=new Thread_C(2,"二线程 ");
Thread_C t3=new Thread_C(3,"三线程 ");
Thread_C t5=new Thread_C(5,"五线程 ");
//注意:上述仅仅构造出线程对象,尚未启动
t2.start();t3.start();t5.start();
System.out.print("main结束.\n "); }
}
- 引入线程的目的:旨在实现并发程序设计。
- 并发程序设计的目的:
- 现实中,有很多并发需求,无法用顺序型程序实现,如游戏中二人对打、模拟核爆炸
- 并发能提高资源的使用效率,如输入输出占用CPU少,可将相关CPU时间片分给其它计算任务
-
OS中,进程实现了任务间的并发,线程实现了任务内的并发(即程序员决定如何并发)
如:在线播放音视频,需要先下载到缓存,再播放。
类似这种并发,只能由程序员决定何时进行那个操作,
不能播放、下载不能以任意次序进行,即OS不知晓二者是何种关 -
单个线程的执行是顺序的,多个线程执行结果不确定的原因是:
多个线程(即若干条语句)在不确定的时间、不确定的位置进行了交错
如:线程1有三条语句:a、b、c;线程2有2条语句:x、y
可能的执行结果有axybc、axbcy、xabcy、…… -
线程由三要素组成:
① 虚拟CPU(即Thread类)
② 线程体(Runnable接口中的run)
③ 共享资源
注意:三者必须同时具备。类比:线程就是【行驶中】的汽车 虚拟CPU–汽车;线程体—司机或智能驾驶机器人;共享资源 — 道路;