线程基础
- 每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销。
- 线程可以看成是轻量级的进程,属于同一进程的线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小。
- 线程和进程最根本的区别在于:进程是资源分配的单位,线程是调度和执行的单位。
- 多进程: 在操作系统中能同时运行多个任务(程序)。
- 多线程: 在同一应用程序中有多个顺序流同时执行。
- 线程是进程的一部分,所以线程有的时候被称为轻量级进程。
- 一个没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个线程,进程的执行过程不是一条线(线程)的,而是多条线(线程)共同完成的。
- 系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源。那就是说,除了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。
线程状态
----新生状态(New)
用new关键字建立一个线程对象后,该线程对象就处于新生状态。
处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态。
----就绪状态(Runnable)
处于就绪状态的线程已经具备了运行条件,但是还没有被分配到CPU,处于“线程就绪队列”,等待系统为其分配CPU。就绪状态并不是执行状态,当系统选定一个等待执行的Thread对象后,它就会进入执行状态。一旦获得CPU,线程就进入运行状态并自动调用自己的run方法。有4中原因会导致线程进入就绪状态:
- 新建线程:调用start()方法,进入就绪状态;
- 阻塞线程:阻塞解除,进入就绪状态;
- 运行线程:调用yield()方法,直接进入就绪状态;
- 运行线程:JVM将CPU资源从本线程切换到其他线程。
----运行状态(Running)
在运行状态的线程执行自己run方法中的代码,直到调用其他方法而终止或等待某资源而阻塞或完成任务而死亡。如果在给定的时间片内没有执行结束,就会被系统给换下来回到就绪状态。也可能由于某些“导致阻塞的事件”而进入阻塞状态。
----阻塞状态(Blocked)
阻塞指的是暂停一个线程的执行以等待某个条件发生(如某资源就绪)。有4种原因会导致阻塞:
- 执行sleep(int millsecond)方法,使当前线程休眠,进入阻塞状态。当指定的时间到了后,线程进入就绪状态。
- 执行wait()方法,使当前线程进入阻塞状态。当使用nofity()方法唤醒这个线程后,它进入就绪状态。
- 线程运行时,某个操作进入阻塞状态,比如执行IO流操作(read()/write()方法本身就是阻塞的方法)。只有当引起该操作阻塞的原因消失后,线程进入就绪状态。
- join()线程联合: 当某个线程等待另一个线程执行结束后,才能继续执行时,使用join()方法。
----死亡状态(Terminated)
死亡状态是线程生命周期中的最后一个阶段。线程死亡的原因有两个。一个是正常运行的线程完成了它run()方法内的全部工作; 另一个是线程被强制终止,如通过执行stop()或destroy()方法来终止一个线程(注:stop()/destroy()方法已经被JDK废弃,不推荐使用)。当一个线程进入死亡状态以后,就不能再回到其它状态了。
基本使用
1-- 继承Thread类(java.lang.Thread)实现多线程, 每个线程都是通过某个特定的Thread对象所对应的方法run( )来完成其操作的,方法run( )称为线程体,通过调用Thread类的start()方法来启动一个线程。
2-- 继承Runnable类,在实现Runnable接口的同时还可以继承某个类,所以更为常用
//线程问题多,不安全,需要改良;仅用于演示一些基本用法
public class Web12306 implements Runnable{
private int ticketNums = 99; //票数
boolean live = true; //标记变量,表示线程是否可中止;
@Override
public void run() {
while(live) {
if(ticketNums<=0) {
live = false;
return;
}
// 模拟网络延迟Thread.sleep(200),继而可能会产生问题,所以要通过同步解决
System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);
}
}
public void terminate() {//控制线程是否运行
live = false;
}
public static void main(String[] args) {
//一份资源
Web12306 web = new Web12306();
Thread mh = new Thread(web,"码蟥");//新生状态
System.out.println(Thread.currentThread().getName());//获取主线程名称main
//多个代理
new Thread(web,"码畜").start();
new Thread(web,"码农").start();
mh.start();//就绪状态
for(int i=0;i<100;i++) {
System.out.println("主线程main" + i);
}
System.out.println(mh.isAlive()); //判断线程是否运行true
web.terminate(); //一种终止线程的方式
System.out.println("web stop");
System.out.println(mh.isAlive()); //判断线程是否运行false
}
}