多线程

多线程

第一章:进程和线程
  1. 进程的介绍

    只有真正运行时程序才被成为进程。单核的cpu在任何时间点上只能运行一个进程,宏观上并行,微观上串行。是一个程序运行状态和资源占用(内存,cpu)的描述。进程是程序的一个动态过程,他指的是从代码加载到执行完毕的一个完整的过程。

    a.独立性: 不同的进程之间是相互独立的。

    b. 动态性: 进程在系统中不是静止不动的,而是在系统中一直活动的。

    c. 并发性: 多个进程可以在单个处理器上同时进行,且相互不影响。

  2. 线程的介绍

    线程是进程的一部分,一个进程可以分为多个线程,每个线程去处理一个特定的子任务。

    线程的执行是抢占式的,多个线程在同一个进程中并发执行,其实就是cpu快速的在不同的线程之间的切换,也就是说,当前运行的线程在任何时候都有可能被挂起,以便另一个线程可以运行。

    并发执行,轮转交替。

    举例:迅雷是一个进程,当中多个下载任务即是多个线程。
    Java虚拟机是一个进程,当中默认包含主线程(Main),可通过代码创建多个独立的线程,与Main并发执行。

    线程的组成部分:

    • cpu时间片:操作系统(os)会为每个线程分配执行的时间
    • 运行数据:
      • 堆空间:存储线程需使用的对象,多个线程可以共享堆中的对象(重要)
      • 栈空间:存储线程需要使用的局部变量,每个线程都拥有独立的栈。(重要)
    • 线程的逻辑代码
  3. 进程和线程的关系和区别

    a.一个程序运行后至少有一个进程

    b.一个进程可以包含多个线程,但是至少需要有一个线程,否则这个进程是没有意义的

    c.进程间不能共享资源,但线程之间可以

    d.系统创建进程需要为该进程重新分配系统资源,而创建线程则容易的多,因此使用线程实现多任务并发比多进

    程的效率高

第二章:多线程的实现
  1. 继承Thread类
    继承Thread类,Thread类是所有线程的父类,实现了对线程的抽取和封装。
    
    继承Thread类创建并启动多线程的步骤:
    	1. 定义一个类,继承Thread类,重写run方法,该方法的方法体就表示了该线程要完成的任务
    	2. 创建Thread子类的对象,即创建了子线程
    	3. 用线程对象的start方法启动该线程
    

    代码实现:

    public class TestCreateThread {
    
    	public static void main(String[] args) {
    		MyThread my = new MyThread();
    		my.start();
    	}
    }
    class MyThread extends Thread{
    	public void run(){
    		for (int i = 0; i < 50; i++) {
    			System.out.println("MyThread:"+i);
    		}
    	}
    }
    
  2. 实现Runnable接口
    实现Runnable接口创建并启动多线程的步骤: 
    	a.定义一个Runnable接口的实现类,并重写该接口中的run方法,该run方法的方法体同样是该线程的线程执行体 
    	b.创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象
    	c.调用线程对象的start方法来启动该线程
    
    

    代码实现:

    public class TestCreateThread {
    	public static void main(String[] args) {
    		MyRunnable mr = new MyRunnable();
    		Thread t2 = new Thread(mr);
    		t2.start();
    	}
    }
    class MyRunnable implements Runnable{
    	@Override
    	public void run() {
    		for (int i = 0; i <= 50; i++) {
    			System.out.println(i);
    		}
    	}
    }
    
线程创建的2种方法的比较
实现Runnable接口的方式 
	a.线程类只是实现了Runnable接口,还可以继承其他类【一个类在实现接口的同时还可以继承另外一个类】 
	b.可以多个线程共享同一个target对象,所以非常适合多个线程来处理同一份资源的情况 
	c.弊端:编程稍微复杂,不直观,如果要访问当前线程,必须使用Thread.currentThread() 

继承Thread类的方式
	a.编写简单,如果要访问当前线程,除了可以通过Thread.currentThread()方式之外,还
	可以使用 super关键字 
	b.弊端:因为线程类已经继承了Thread类,则不能再继承其他类【单继承】 实际上大多数的
	多线程应用都可以采用实现Runnable接口的方式来实现【推荐使用匿名内部类】
调用start和run方法的区别
	当调用start()方法时将创建新的线程,并且执行run()方法里的代码,但是如果直接调用start()方法,不会创 建新的线程也不会执行调用线程的代码
第三章:线程中常用的方法
 1. 休眠:
    public static void sleep(long millis)
    //当前线程主动休眠millis毫秒,使得当前正在执行的线程休眠一段时间,释放时间片,导致		线程进入阻塞状态 sleep(5000),5000的单位是毫秒,设置了sleep就相当于将当前			线程挂起5s,这个操作跟线程的优先级无关, 当对应的时间到了之后,还会再继续执行
  2. 放弃(让步):
    public static void yield()
    //当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片,可以让当前正在执行的线程暂		停,但它不会阻塞该线程,他只是将该线程转入就绪状态,完全可能出现的情况是:当某个	线程调	用了yield方法暂停之后,线程调度器又将其调度出来重新执行 实际上,当某个线程	调用了yield方法暂停之后,只有优先级与当前线程相同,或者优先级比当前线程更高的就绪		状 态的线程才会获得执行的机会
  3. 结合:
    public final void join()
    //允许其他线程加入到当前线程中,并优先执行
    在执行原来线程的过程中,如果遇到了合并线程,则优先执行合并进来的线程,执行完合并进	 来的线程后,再回到原 来的任务中,继续执行原来的线程 特点: a.线程合并,当前线程一定	 会释放cpu时间片,cpu会将时间片分给要Join的线程 b.哪个线程需要合并就在当前线程中,添	 加要合并的线程 c.join之前,一定要将线程处于准备状态start
  4. 守护线程 setDaemon(true)  判断是否是守护线程isDaemon()
  	特征:如果所有的前台线程都死亡,后台线程会自动死亡,必须要在start之前执行
  5. 设置线程的优先级setPriority() 默认为5
      在java中线程优先级分为1~10,如果小于1或者大于10,则jdk报                                    illegalArgumentException()异常非法参数异常
  6. 设置线程的名字:thread.setName("主线程"); 
第四章:线程的生命周期
	对于线程,当线程被创建并启动之后,它既不是一启动就进入了执行状态,也不是一直处于执
行状态,在线程的生命周期中,他会经历各种不同的状态【在一个进程中,多个线程同时运行,是在争抢CPU时间片】

New(新生):线程被实例化,但是还没有开始执行

Runnable(就绪):没有抢到时间片

Running(运行):抢到了时间片,CPU开始处理这个线程中的任务

Blocked(阻塞): 线程在执行过程中遇到特殊情况,使得其他线程就可以获得执行的机会,被阻塞的线程会等待合适的时机 重新进入就绪状态

Dead(死亡):线程终止

​ 1. run方法执行完成,线程正常结束【正常的死亡】

​ 2. 直接调用该线程的stop方法强制终止这个线程

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值