什么是进程,什么是线程?
概念:进程是一个应用程序(即一个进程可以看成是一个软件)线程则是一个进程中的执行单元。
进程和线程是什么关系
- 一个进程可以启动多个线程。举个例子:假设京东是一个进程,那么刘强东哥哥可以看作是京东的一个线程,奶茶妹妹也可以看作是京东的一个线程。
- 不同进程之间的内存独立不共享。举个例子:阿里巴巴和京东是不同的进程,他们之间的资源不共享,他们是独立的。
多线程的作用:提高程序的处理效率
还是同样举个例子:车站的每个售票窗口看做一个线程,每个窗口都是可以购票的,窗口A和窗口B之间不会互相干扰到,甲在窗口A买票,乙在窗口B买票,甲不需要等乙,乙不需要等甲。这就是所谓的多线程并发。一个线程的结束不会影响另一个线程。
线程的内存图
实现线程的几种方式
这里需要先介绍一个类。Thread类,即线程类,这个类java已经帮我们实现了,所以后续我们实现线程会更加方便。
Thread类的有关方法
- run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
- currentThread():静态方法 返回执行当前代码的线程
- getName() 获取当前线程的名字
- setName()设置当前线程的名字
- yield() 释放当前cpu的执行权
- join() 在线程A中调用线程B的join(),此时线程A就进入阻塞状态,知道线程B完全执行完以后,线程A才结束阻塞状态
sleep(long millitime) - isAlive()判断当前线程是否存活
以上方法的总结来源于这个博主
以下是实现线程的方法:
- 编写一个类,直接继承java.lang.Thread类,重写run方法(注意:run方法必须重写)
例子:
public class TestThread01 {
public static void main(String[] args) {
//这里是main方法,这里的代码属于主线程,在主栈中运行
//新建一个分支线程对象
MyThread myThread =new MyThread();
myThread.start();//启动线程,启动成功的线程会自动调用run方法,并且run方法在分支栈的栈底部(压栈)
//以下的代码还是运行在主线程中
for(int i=0;i<10;i++) {
System.out.println("主线程----->"+i);
}
}
}
class MyThread extends Thread{
@Override
public void run() {
//这段程序运行在分支线程中(分支栈)
for(int i=0;i<10;i++) {
System.out.println("分支线程------>"+i);
}
}
}
- 编写一个类,实现java.lang.Runnable接口,实现方法
例子:
public class TestThread02 {
public static void main(String[] args) {
Thread t=new Thread(new MyRunnable());
//启动线程
t.start();
for(int i=0;i<10;i++) {
System.out.println("主线程----->"+i);
}
}
}
class MyRunnable implements Runnable{
public void run() {
for(int i=0;i<10;i++) {
System.out.println("分支线程----->"+i);
}
}
}
- 采用匿名内部类创建线程对象(这种方式不常用)
public class TestThread03 {
public static void main(String[] args) {
Thread t =new Thread(new Runnable()
{
public void run() {
for(int i=0;i<10;i++) {
System.out.println("分支线程---->"+i);
}
}
});
t.start();
for(int i=0;i<10;i++) {
System.out.println("主线程---->"+i);
}
}
}
注意:第二种方式比较常用,因为一个类实现了接口,以后还能继承别的类,更加灵活。而第一种方式继承了类以后就不能再继承别的类了
关于线程对象的生命周期
①新建状态②就绪状态③运行状态④阻塞状态⑤死亡状态
1、一个刚new出来的线程对象处于新建状态
,当它调用start方法后就会进入就绪状态
,就绪状态的线程又叫可运行状态,表示当前线程具有抢夺cpu时间片的权利(cpu时间片就是执行权)
。
2、当一个线程抢夺到cpu时间片之后,就开始执行run方法,run方法的开始执行标志着线程进入运行状态
。
3、进入运行状态后,当之前占有的cpu时间片用完之后,会重新回到就绪状态继续抢夺cpu时间片,当再次抢到cpu时间片之后,会重新进入run方法接着上一次的代码继续执行(即上一次运行状态的代码运行到哪里,这一次就会接着上一次继续运行)。
4、当一个线程遇到阻塞事件,例如:接受用户键盘输入,或者sleep方法等,此时线程会进入阻塞状态
,阻塞状态的线程会放弃之前占有的cpu时间片,此时就需要再回到就绪状态继续抢夺cpu时间片,当run方法结束后,线程对象进入死亡状态
上面这一图来源于这里
获取当前线程对象、修改线程对象的名字
currentThread( )方法获取当前线程对象、getName( )方法获取线程对象的名字、setName( )方法修改线程对象的名字
public class TestThread04 {
public static void main(String[] args) {
Thread ct = Thread.currentThread(); //创建线程对象,并获取当前线程对象
System.out.println(ct.getName());
MyThread2 t = new MyThread2(); // 创建线程对象
String s1 = t.getName(); // 获得线程名字
System.out.println(s1);
t.setName("t1"); // 修改线程名字
String s2 = t.getName();
System.out.println(s2);
MyThread2 t2 = new MyThread2();
t2.setName("t2");
t2.start();
t.start();
for (int i = 0; i < 10; i++) {
System.out.println("主线程-----》" + i);
}
}
}
class MyThread2 extends Thread {
public void run() {
for (int i = 0; i < 10; i++) {
Thread ct = Thread.currentThread();
// 获取的是当前线程对象,哪个线程start()就是哪个线程对象
// 例:当t1线程start,那么这里的当前线程就是t1
System.out.println(ct.currentThread() + "----->" + i);
}
}
}
如果觉得您有帮助的话,麻烦给我点个赞叭~
To be continue …