@TOC

线程简介

进程与线程

进程(Process) 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。

线程(thread) 是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

简单来说:
进程:指在系统中正在运行的一个应用程序;程序一旦运行就是进程;进程——资源分配的最小单位。

线程:系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。线程——程序执行的最小单位。

并发

当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。.这种方式我们称之为并发(Concurrent)。
因此,多个线程时轮询执行的。

线程状态

线程可以分为五种状态:

  • New 新建
  • Runnable 就绪
  • Running 运行
  • Blocked 阻塞
  • Dead 死亡

线程生命周期

在这里插入图片描述

  1. 新建
    new Thread()
    线程类 :Thread 类 和 Thread子类
  2. 就绪
    调用了 start() 方法会进入到 就绪状态,等待cpu的调用执行;
  3. 运行
    处于就绪状态的 线程 被cpu调用执行了,就处于了运行状态。
  4. 阻塞
    处于运行状态的线程由于某些原因暂停了 cpu的调用执行。
    • sleep:
      sleep(毫秒时间) 等待
      当线程A 调用了sleep方法,那么线程A处于阻塞状态,当阻塞的时间到了,那么 恢复到就绪状态,cpu调用执行。
    • join:
      join() :让其它线程先执行。
      线程A 中 调用了 线程B的join方法,那么线程A需要等待线程B执行完,再执行,线程A再等待线程B执行的过程中 就 处于了阻塞状态,当线程B执行完毕了,线程A恢复到就绪状态,cpu调用执行。
    • 同步
    • wait()
  5. 死亡
    线程正常 或 异常结束。

线程实现

主线程:程序启动后,最先 启动的一个线程。

主线程任务 在 main()中
是启动其它线程的线程。
	public static void main(String[] args) {
		// 获得当前正在运行的线程
		System.out.println(Thread.currentThread());// Thread[main,5,main]
		System.out.println(Thread.currentThread().getName());// 名字
		
	}

子线程
创建子线程有三种方式:

  1. 继承Thread类
    子线程 默认的名字: Thread-N (N表示第几个线程)
class StudentThread extends Thread{
	public StudentThread(String name){
		super(name);
	}
	@Override
	public void run() {
		for(int i = 0;i < 5; i++)
			System.out.println(Thread.currentThread() + ":" + i);
	}
}
public class TestThread {

	public static void main(String[] args) {
		StudentThread stThread = new StudentThread("Tom");
		stThread.start();

	}

}

输出:

Thread[Tom,5,main]:0
Thread[Tom,5,main]:1
Thread[Tom,5,main]:2
Thread[Tom,5,main]:3
Thread[Tom,5,main]:4

  1. 实现Runnable接口(一般使用这种方式)
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
class StudentThread implements Runnable{
	@Override
	public void run() {
		for(int i = 0;i < 5; i++)
			System.out.println(Thread.currentThread() + ":" + i);
	}
}
public class TestThread {

	public static void main(String[] args) {
		// 不是线程类的对象
		StudentThread studentThread = new StudentThread();
		// 新建线程
		Thread thread = new Thread(studentThread,"st");
		thread.start();
	}

}

输出:

Thread[st,5,main]:0
Thread[st,5,main]:1
Thread[st,5,main]:2
Thread[st,5,main]:3
Thread[st,5,main]:4
  1. 实现 Callable接口
@FunctionalInterface
public interface Callable<V> { // V 是返回值类型
  
    V call() throws Exception;
}
class StudentThread implements Callable<Integer>{

	@Override
	public Integer call() throws Exception {
		int sum = 0;
		for(int i = 0; i < 5; sum+=i,i++)
			System.out.println(Thread.currentThread() + " " + i);
		return sum;
	}
	
}
public class TestThread {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		StudentThread studentThread = new StudentThread();
		//用来得到返回值
		FutureTask<Integer> futureTask = new FutureTask<>(studentThread);
		Thread thread = new Thread(futureTask,"st");
		thread.start();
		System.out.println(futureTask.get());
	}

}

输出:

Thread[st,5,main] 0
Thread[st,5,main] 1
Thread[st,5,main] 2
Thread[st,5,main] 3
Thread[st,5,main] 4
10

三种实现方式的比较

  • 不利于资源的共享:
    继承Thread类.
  • 实现资源的共享:
    实现Runnale接口
    实现Callable接口
实现Runnable接口实现Callable接口
run()call()
不能抛异常可以抛异常
没有返回值有返回值,通过方法来获得返回值,也可以知道线程运行的状态。

多线程实现

class OneThread implements Runnable{

	@Override
	public void run() {
		for(int i = 0;i < 5;i++)
			System.out.println(Thread.currentThread() + ":" + i);
	}
	
}

public class TestMoreThread {

	public static void main(String[] args) {
		OneThread oneThread = new OneThread();
		Thread first = new Thread(oneThread,"first");
		Thread second = new Thread(oneThread,"second");
		first.start();
		second.start();
	}
}

输出:

Thread[second,5,main]:0
Thread[first,5,main]:0
Thread[first,5,main]:1
Thread[first,5,main]:2
Thread[second,5,main]:1
Thread[first,5,main]:3
Thread[first,5,main]:4
Thread[second,5,main]:2
Thread[second,5,main]:3
Thread[second,5,main]:4

主线程与子线程:

class OneThread implements Runnable{

	@Override
	public void run() {
		for(int i = 0;i < 5;i++)
			System.out.println(Thread.currentThread() + ":" + i);
	}
	
}

public class TestMoreThread {

	public static void main(String[] args) {
		OneThread oneThread = new OneThread();
		Thread first = new Thread(oneThread,"first");
		Thread second = new Thread(oneThread,"second");
		first.start();
		second.start();
		
		System.out.println("主线程结束");
	}
}

输出:

主线程结束 
Thread[first,5,main]:0
Thread[second,5,main]:0
Thread[second,5,main]:1
Thread[first,5,main]:1
Thread[second,5,main]:2
Thread[first,5,main]:2
Thread[second,5,main]:3
Thread[first,5,main]:3
Thread[second,5,main]:4
Thread[first,5,main]:4

期望的输出是子线程输出完毕之后输出主线程结束,上述输出与期望结果不符,这是因为当主线程执行到输出语句时子线程没有结束,
要想得到期望的结果,有下面两种方式:

  1. 使用sleep()
public class TestMoreThread {

	public static void main(String[] args) {
		OneThread oneThread = new OneThread();
		Thread first = new Thread(oneThread,"first");
		Thread second = new Thread(oneThread,"second");
		first.start();
		second.start();
		try {
			Thread.sleep(1);//毫秒
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("主线程结束");
	}
}

使用sleep使主线程睡眠,子线程在1毫秒内执行完成,之后执行主线程,输出
不过用这种方式的话,如果子线程无法在sleep时间内执行完成,主线程的输出会穿插在子线程的输出中
想要使主线程必在子线程执行完后执行可以使用join(),让子线程先执行

public class TestMoreThread {

	public static void main(String[] args) {
		OneThread oneThread = new OneThread();
		Thread first = new Thread(oneThread,"first");
		Thread second = new Thread(oneThread,"second");
		first.start();
		second.start();
		try {
			first.join();
			second.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("主线程结束");
	}
}

输出:

Thread[first,5,main]:0
Thread[second,5,main]:0
Thread[first,5,main]:1
Thread[first,5,main]:2
Thread[second,5,main]:1
Thread[first,5,main]:3
Thread[second,5,main]:2
Thread[first,5,main]:4
Thread[second,5,main]:3
Thread[second,5,main]:4
主线程结束

线程的优先级

  1. 理论上,优先级高的线程比优先级低的线程获得更多的CPU时间
  2. 实际上,线程获得的CPU时间由包括优先级在内的多个因素决定
  3. 理论上,等优先级的线程有同等的权力使用CPU

线程优先级从1——10

	/**
     * 线程可以获得的最低优先级
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * 线程的默认优先级
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * 线程可以获得的最高优先级
     */
    public final static int MAX_PRIORITY = 10;

设置线程优先级:

//设置优先级
first.setPriority(10);//1 - 10
//获得优先级
first.getPriority();

Q.E.D.