创建线程的两种方式
先来了解一下与线程相关的概念,如程序,进程,以及他们之间的区别
1)、程序Program:
程序是一段静态的代码, 它是应用程序执行的蓝本。
2)、进程Process
进程是指一种正在运行的程序, 有自己的地址空间。
3)、线程Thread
进程内部的一个执行单元, 它是程序中一个单一的顺序控制流程。线程又被称为轻量级进程(lightweight process)。如果在一个进程中同时运行了多个线程, 用来完成不同的工作, 则称之为多线程。
线程的特点:
- 轻量级进程
- 独立调度的基本单位
- 可并发执行
- 共享进程资源
4)、进程与线程的区别
区别 | 进程 | 线程 |
---|---|---|
根本区别 | 作为资源分配的最小单位 | 作为资源调度和执行的最小单位 |
开 销 | 每个进程都有独立的代码和数据空间(进程上下文), 进程间的切换会有较大的开销。 | 线程可以看成时轻量级的进程, 同一类线程共享代码和数据空间, 每个线程有独立的运行栈和程序计数器(PC), 线程切换的开销小。 |
所处环境 | 在操作系统中能同时运行多个任务(程序) | 在同一应用程序中有多个顺序流同时执行 |
分配内存 | 系统在运行的时候会为每个进程分配不同的内存区域 | 除了CPU之外, 不会为线程分配内存(线程所使用的资源是它所属的进程的资源) , 线程组只能共享资源 |
包含关系 | 没有线程的进程是可以被看作单线程的, 如果一个进程内拥有多个线程, 则执行过程不是一条线的, 而是多条线(线程) 共同完成的。 | 线程是进程的一部分, 所以线程有的时候被称为是轻权进程或者轻量级进程。 |
5)、线程的生命周期
(json插队方法,属于对象 t1.join()表示必须等到t1线程执行完,才执行其他线程,t1执行的时候,其他线程都是属于阻塞状态)
1、新生状态 (一旦开启了新生状态,线程就有了自己的工作空间)
2、就绪状态(等待cpu调度,调用start方法)yield让出cpu的调度直接从运行状态转换到就绪状态、时间片用完由运行变就绪状态、jvm算法切换
3、运行状态(cpu调度到改线程)
4、阻塞状态(如,执行sleep方法,wait,或同步代码锁、join方法)
5、死亡状态(线程正常执行完毕,或者调用stop方法【不推荐,线程不安全】,通过标识符 使用terminate方法)
1)、创建线程的第一种方式:
继承Thread
类,重写run
方法
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("当前线程的名字--->"+Thread.currentThread().getName());
}
public static void main(String[] args) {
//创建4个线程
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
MyThread t4 = new MyThread();
//开启线程
t1.start();
t2.start();
t3.start();
t4.start();
System.out.println("当前线程的名字--->"+Thread.currentThread().getName());
}
}
输出结果:
当前线程的名字--->main
当前线程的名字--->Thread-0
当前线程的名字--->Thread-1
当前线程的名字--->Thread-3
当前线程的名字--->Thread-2
这里线程的执行顺序并不是按照我们 执行start()
的顺序,因为start()
方法,并不是代表立即去执行线程,只不过是告诉cpu
我可以被调度,至于它先执行哪个线程,要靠cpu去决定。(但是我们可以设置一个优先级,优先级高的显被执行的概率大,但是不是绝对的)
2)、创建线程的第二种方式:
实现Runnable
接口。重写run
方法
public class MyRanableThread implements Runnable
{
@Override
public void run() {
System.out.println("当前线程的名字--->"+Thread.currentThread().getName());
}
public static void main(String[] args) {
Thread t1 = new Thread(new MyRanableThread());
t1.start();
new Thread(new MyRanableThread()).start();
new Thread(new MyRanableThread()).start();
new Thread(new MyRanableThread()).start();
}
}
执行结果:
当前线程的名字--->Thread-2
当前线程的名字--->Thread-0
当前线程的名字--->Thread-1
当前线程的名字--->Thread-3
通过Thread
的构造方法传入Runnable
接口的实现类,然后执行start()
方法,开启线程,相对于第一种方式,这里的Thread
其实就是个静态代理对象。
那么两种的方式有什么区别呢
执行了start()
方法之后,当线程被cpu
调度之后,就会执行run()
方法,进入Thread
这个类,看一下run()
方法的源码(部分):
class Thread implements Runnable //thread类其实也是实现了Ruanable接口
/* What will be run. */
private Runnable target;
@Override
public void run() {
if (target != null) {
target.run();
}
}
原来当我们使用第一种方法 继承Thread
类,重写run
方法,在调用run
方法的时候,必然就会调用子类重写的run
方法,然后执行。但当我用第二种方法,也就是Thread
构造传入Runnable
接口的实现类之后,当我们要执行run
方法,会先判断target
是否为空,然后执行target.run()
,也就是我们实现Runnable
时候所重写的run
方法。
还没有评论,来说两句吧...