线程

xiaoxiao2021-02-28  112

进程(Process):

当一个程序进入内存运行时,即变成一个进程。 独立性:时系统中独立存在的实体。 动态性:程序是静态的,而每一个进程都拥有自己私有的地址空间。 并发性:多个进程可以在单个处理器上并发执行。

线程(Thread):

也被称为轻量级进程。多线程拓展了多进程的概念,使得同一个进程可以同时并发处理多个任务。线程是进程的执行单元。 一个进程可以拥有多个线程,一个线程必须拥有一个父进程。 线程可以拥有自己的堆栈、自己的程序计数器和局部变量,但不拥有系统资源。

多线程的优点:进程之间不能共享内存,但线程之间可以; 创建一个线程占用的系统资源少。

创建线程的三种方法:

1.继承Thread或其子类,重写run方法。 创建Thread子类实例就是创建了线程对象。 2.实现Runnable接口,重写run方法,该run方法同样是该线程的执行体,创建Runnable实现类的实例,并以此作为Thread的target来创建Thread对象。 3.使用Callable和Future创建线程,Callable接口提供了一个call方法,比run方法功能更强大:call()方法可以有返回值、可以声明抛出异常。FutureTask类实现了Futuer接口和Runnable接口,可以作为Thread类的target。 FutureTask task=new FutureTask<>((Callable) ()->{ int i=0; for(;i<10;i++){ System.out.println(Thread.currentThread().getName()+”i的值:”+i); } return i; });

对比: Runnable和Callable: 还可以及继承其他类;多个线程可以共享一个target对象实现多个线程来处理同一分资源的情况; 必须使用Thread.currentThread()访问当前线程。 Thread: 不能在继承其他类; 直接使用this可以访问当前线程。 currentThread()是Thread的静态方法,总是返回当前正在执行的线程对象; getName()是Thread类的实例方法,返回调用该方法的线程的名字。 thread中的实例变量并不会被共享,因为new 一个新的线程时便创建了一个新的实例。 而target中是同一个Runnable对象,所以便于共享。

线程的生命周期:

新建(New): 就绪(Runnable): 运行(Running): 阻塞(Blocked): 死亡(Dead): 启动线程如果直接调用对象run方法:run方法会被立即执行,run返回之前其它线程无法并发执行。相当于系统把线程对象当成了普通对象,run方法也变成了普通方法,而不是线程执行体。 start方法只能被调用一次,而且是用来调用处于新建状态的线程。否则会引发IllegalThreadStateException异常。

当主线程结束时,其他线程并不受任何影响。一旦子线程启动起来后,就拥有和主线程相同的地位,不会受主线程的影响。 isAlive():判断线程是否已经死亡,新建(start之前)和死亡状态返回false。 stop方法可以用来结束线程,但容易导致死锁。

线程控制:

join():让一个线程等待另一个线程完成。 thread.join() 表示等thread线程执行完才会继续执行。 后台线程:其他线程提供服务的线程。例如JVM垃圾回收线程。 如果所有前台线程死亡,后台线程自动死亡。 sleep():让当前正在执行的线程暂停一段时间,但并不会释放对象锁。Thread类提供的静态方法,会使线程进入阻塞状态到时间后再进入就绪状态。 yield():线程让步,Thread类提供的静态方法,但不会阻塞该线程。转入就绪状态。此时优先级大于等于该线程的线程才会获得执行机会。(抢占式) 改变线程优先级:每个线程默认的优先级都与创建它的父线程优先级相同。 mian线程具有普通优先级 setPriority(1~10)。 getPriority().

线程同步:

同步代码块:run{synchronized(obj){ } } 写在run方法中。 加锁-》修改-》释放锁

同步方法:使用synchronized关键字修饰的方法。 在run方法中调用同步方法。 对于synchronized修饰的实例方法,无须显式指定同步监视器,同步方法的同步监视器是this,也就是调用该方法的 对象。(StringBuilder单线程和StringBuffer多线程) 如果修饰静态方法,则相当于申请当前对象的 Class 锁

释放锁:wait(), Object方法,会释放同步监视器。

同步锁(Lock): lock使用显式Lock对象作为同步锁。 synchronized使用于竞争资源相关的、隐式的同步监视器,要求加锁和释放锁要出现在同一块结构中,当获得多个锁时,必须以相反顺序释放。 同样符合 加锁–修改–释放锁 的操作模式。(ReentrantLock可重入锁)

死锁:线程类的suspend() 挂起 方法容易导致死锁。 (resume)

sleep、yield、wait、suspend区别。

线程通信:

wait()、notify()、notifyAll() 属于Object类。必须由同步监视器对象(synchronized)调用。 对于同步方法,该类的默认实例this就是同步监视器;对于同步代码块,同步监视器是synchronized后括号里的对象,必须使用该对象调用这三个方法。

使用Condition:对于直接使用Lock对象保证同步,系统中不存在隐式的同步监视器,也就不能使用wait()、notify()、notifyAll()方法。 Condition实例被绑定在一个Lock对象锁上,调用Lock.newCondition()获得该实例。 Condition提供await() signal() signalAll()方法。

阻塞队列BlockingQueue: Queue子接口。当生产者线程试图向BlockingQueue放入元素时,如果队列已满,则该线程被阻塞;当消费者试图从BlockingQueue取元素时,如果队列已空,则该线程被阻塞。 两个线程交替放和取元素,从而控制线程通信。 put(E e) take()

线程池:

系统启动一个新线程的成本较高,因为涉及与操作系统的交互。 线程池在系统启动时即创建大量空闲线程,程序将一个Runnable对象或callable对象传给线程池,线程池会启动一个线程来执行run或call方法。当run或call方法执行结束后,该线程不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个run或call。

转载请注明原文地址: https://www.6miu.com/read-37415.html

最新回复(0)