什么是进程?
进程是电脑里正在运行的一个程序。例如:eclipse、记事本、chrome。
进程是系统分配资源的最小单位。

什么是线程?
一个进程里可以包含多个线程,每个线程负责完成一个任务。
线程是程序调度的最小单位。
一个进程里至少要包含一个线程,这个线程叫主线程。

单线程:如果你不创建新的线程,程序就是单线程的,所有代码都在主线程里执行。

多线程:除了系统自动产生的主线程之外,你又额外创建了一些线程。当线程个数比1个多的时候,称为是多线程。

什么时候需要使用多线程呢?
答:(1)当你有多个任务需要执行,但是任务与任务之间可以独立进行的时候,可以使用多线程,这样做可以充分利用电脑(CPU)提高程序的运行效率。
(2)有一个任务特别耗时,我们可以为耗时的任务单独分配一个线程,这样的话,就不会影响其他任务的执行。

Java程序如何实现多线程?
1、建一个类继承于Thread,重写run方法
第一步:创建类继承于Thread
第二步:重写run方法
第三步:创建 对象
第四步:让对象开始执行任务。对象.start()

因为想要在一个新的线程里执行某个任务,必须将任务写在子类的run方法里,而且调用的用时候要使用start方法,又因为一个类只有一个run方法,因此run方法很难被重用。(一个自定义的Thread只创建了一个对象),因此可以考虑使用匿名类。

2、建一个类实现Runnable接口,在实现类里实现run方法。然后把实现类的对象作为Thread的参数。
第一步:创建一个Runnable的实现类
第二步:实现run方法
第三步:创建一个实现类的对象
第四步:把对象作为Thread的参数
第五步:Thread对象调用start方法。

通常也是使用匿名类来完成实现类对象的创建。

线程分为2类:
一类叫用户线程。
另一类叫守护线程。

守护线程是为用户线程服务的。如果用户线程没了,守护线程立即结束。
在java程序里,任何一个程序至少包含2个线程,一个是主线程,一个是gc回收的线程,gc回收线程在守护线程里执行。当所有用户线程结束时(任务执行完了,中途退出了),守护线程自动完结。当所有用户线程结束时,进程也会结束。

线程的状态
new状态:线程刚创建完毕,尚未调用start方法。
对应的代码是 Thread t = new Thread();//或自定义的子类对象刚创建出来。

runnable状态:可运行的(尚未运行)。
t.start()。已经在等待被皇上(CPU)翻牌了。

running状态:正在被CPU宠幸(正在执行)。

block(阻塞)状态:主动或者被动暂停线程运行。(你暂停了,意味着你把cpu让给别人用了。)

dead状态:你的任务执行完了,或者被exit了。

注意的一点:想要进入running状态,你必须是runnable状态。(要么从new状态进入runnable状态,要么从block状态进入runnable状态。)
start方法只能调用一次。


多线程一般要运用到匿名类

public static void main(String[] args) {
	
	//使用匿名类
	Thread t1 = new Thread("线程1") {
		@Override
		public void run() {
			for(int i = 0; i < 100; i++) {
				System.out.println(
						Thread.currentThread().getName()+":"+i);
			}
		}
	};
	
	Thread t2 = new Thread("线程2") {
		@Override
		public void run() {
			for(int i = 0; i < 100; i++) {
				System.out.println(
						Thread.currentThread().getName()+":helloworld");
			}
		}
	};

	t1.start();
	t2.start();
	
}

//进程:一个正在运行的程序就是一个进程。进程是系统资源分配的最小单位。
//系统只会为正在运行的程序分配资源(计算资源(cpu)+存储资源(内存))。
//每当有一个程序运行的时候,系统会为程序分配一块内存,用于存放程序运行
//期间的所有数据(你定义的各种变量,new的各种对象)。
//CPU会周期性的执行你的程序。(获得了CPU计算资源)。
//进程不是程序执行的单元。程序执行的最小单元是线程。

//一个进程至少要包含一个线程。
//当我们运行程序的时候,
//JVM会创建一个线程(main),这个线程去执行我们的main方法。
//因为Java存在垃圾回收机制,因此任何一个程序在运行的时候,系统
//都会建立一个 守护线程 去执行垃圾回收的代码。

//如果不人为创建新线程,所有代码都会在main线程里执行。因此如果有一个
//耗时任务在运算的时候,后面的代码是无法执行的。如果想让后面的代码不受
//耗时任务的影响,这时候需要额外开辟一个线程,要么让耗时任务在这个线程
//里执行(采用这种方式),要么让后面的代码在这个线程里执行。

//Java实现多线程:
/*

  • 方式一:继承Thread类
  • 步骤:第一步:创建一个Thread子类
  • 第二步:重写run方法
  • 第三步:创建Thread子类的对象
  • 第四步:对象.start();
  • 或者写匿名类。

  • 第二种方式 实现Runnable接口,将对象放入Thread中
  • 步骤:第一步:创建一个类实现Runnable接口
  • 第二步:实现run方法
  • 第三步:创建实现类的对象
  • 第四步:创建一个Thread,将实现类对象作为参数。
  • 第五步:Thread对象.start()

  • 或者使用匿名类


  • 实际开发中,方式二比较常用。
  • 因为第二种方式,可以共享资源。(无需把资源定义为static)

  • */
    //Thread类有一个sleep方法(static方法).
    //它的作用是 让线程休眠。一旦线程休眠了,就自动进入这个线程的阻塞状态
    //sleep休眠的是谁呢?
    //答:Thread.sleep()在哪个线程里,休眠的就是哪个线程。休眠之后
    //Thread.sleep()后面的代码就不暂停执行,等休眠结束后继续执行。

//想要把线程从阻塞状态唤醒,使用Thread的实例方法interrupt。
//被唤醒的线程(回到Runnable状态-就绪状态)等待CPU分配资源,
//一旦拿到cpu,进入Running状态。
//调用一次interrupt只能唤醒一个sleep。Interrupt会抛异常

//jion等待该线程执行完。什么是该线程?谁调用join谁就是该。
//谁等待 该线程? 线程对象.join()这个代码,在哪个线程里运行,
//哪个线程就等待 线程对象把run方法执行完。

//join还可以指定等待多少时间(最长时间)。在最长时间内如果没有执行完
//也不等了。如果执行完了,等待时间没到,结束等待。

//线程同步:
// 在多线程环境下,如果有1个资源被多个线程访问,应该让一个线
//程访问期间,其他线程无法访问。由以前的并行执行变为线性执行。

//java中提供了3种线程同步的解决方案
//方案1:synchronized代码块
//方案2:synchronized方法
//方案3:代码加锁 Lock 注意lock一定要解锁
//(为了确保能解锁,放到finally块中)