合抱之木,生于毫末;九层之台,起于垒土;千里之行,始于足下。-----------送给在码农之路上搬砖的自己。
2018-1-21杭州
补充线程知识
线程的初步认识
- 线程的使用方式:
1.1 继承Thread类,重写run()方法实现自己的业务需求。
1.2 实现Runnable接口,重写run()方法实现自己的业务需求。
1.3 实现Callable接口,重写call()方法,该方法具有返回值。通常与Future/线程池结合 使用。
推荐使用实现Runnable接口的方式,毕竟java类只能单继承,降低了程序的可拓展性和灵活性。
线程的几个基本状态:
1. 新生状态: 线程被创建,且已经分配律内存空间,但是还没有运行。通过调用start()方法可使线程进入运行状态。(!alive)
2. 就绪状态: 线程已经拿到了所有需要的系统资源除了CPU,等待被CPU调度。(alive)
3. 运行状态: 线程拿到了所有需要的系统资源包括CPU,当前线程正在运行。(alive)
4. 阻塞状态: 线程放弃CPU资源,运行需要的资源有些无法获取,等待获取所需要的资源。(alive)
4.1> 等待阻塞:运行的线程执行wait()方法之,JVM会将该线程放入等待池中(会释法锁)
4.2> 同步阻塞:运行的线程获取对象锁时,该锁已经被其他线程占用,JVM会把该线程放入锁池中
4.3> 其他阻塞:运行的线程执行了sleep()、join()、发出I/O请求时,JVM会将该线程状态设置为阻塞状态,当sleep()结束、join()线程执行完/超时、I/O处理完,线程重新进入就绪状态。(不会释法锁)
5. 死亡状态: 当线程完成自己的任务或在运行的过程中出现未捕获的异常中断,线程就会进入死亡状态,这个时候线程还是实例对象,但是它的内存(调用的堆栈)已经溶解。如果再次调用start()去运行,会抛出java.lang.IllegalThreadStateException(非线程状态异常) (!alive)
通过线程isAlive()方法可以获取线程的当前状态。
其中run()方法并没有开启新的线程,只是一个普通方法的执行。
start()方法通过JNI调用线程,才是开启新的线程,实现线程的并发。
并行:两个或者多个事件在同一时刻内执行。(多核CPU同时处理多个任务)
并发:两个或者多个事件在同一时间间隔内执行。(单核CPU处理多个任务)
同步:相关的多进(线)程按照期望的方式相互协调合作。
异步:多进(线)程按照自己独立的,不可预知的速度向前运行。
多线程
- 单线程、多线程、多进程的理解:
1.1 单线程:一个人在自己的桌子上吃饭
1.2 多线程:多个人在同一张桌子上聚餐
1.3 多进程:多个人每个人在自己的桌子上吃饭 - 多线程的调度和使用是一个坑,是否能用好是程序员水平高低的一个标志。
线程同步 synchronized关键字的作用域:
3.1> 某个对象的实例内:synchronized method(){}可以防止多个线程同时访问这个对象的synchronized方法。
3.2> 某个类的范围:synchronized static method(){}防止多线程同时访问这个类的synchronized static 方法,对类的所有对象实例起作用。
3.3> 除了方法用synchronized修饰,synchronized关键字海可以用于方法中某个区域块,表示这个区域块的资源实现互斥访问。用法是:synchronized(this){/区块/},它的作用域是当前对象
3.4> synchronized关键字不能被继承,父类的synchronized method(){}在子类中并不是 synchronized method(){} 而是method(){},子类需要自己主动显示的制定它的方法为synchronized。线程同步:
4.1> 线程同步的目的是保护多个线程访问一个资源时对资源的破坏。
4.2> 线程同步是通过锁来实现的,每个对象有且仅有一个锁,这个锁与一个特定的对象关联,线程一旦获得对象锁,其他访问该对象的线程就无法访问该对象的同步方法。
4.3> 静态同步方法,针对的是这个类,锁对象是该类的对象。静态/非静态方法的锁互不干扰,一个线程获得锁,当在同步方法中访问类其他对象上的同步方法,那该线程就有2个对象锁。
4.4> 同步的关键是,清醒的理解是哪个对象上同步。
4.5> 便携线程安全类,需要时刻注意对多个线程访问资源的逻辑和安全做判断,使之具有原子性,原子操作期间其他的线程无法访问竞争资源。
4.6> 多个线程同时等待一个对象锁时,没有获得对象锁的线程进入阻塞状态。
4.7> 死锁是线程间相互等待锁造成的,一般发生的几率很小,但是一旦发生死锁,程序将死掉线程数据传递的实现:
5.1> 通过构造方法传递数据:在创建线程的时,必须创建一个Thread类或者子类的实例。在线程的start()方法之前,我们已经通过线程类的构造方法将数据传入线程,并将传入的数据通过类变量保存起来,以便线程使用(线程run()方法调用)。
5.2> 通过变量和方法传递数据:普通实体类中的set()方法。
5.3> 通过回调函数传递数据:
@xuweixin
2018-03-03 19:38
字数 2037
阅读 0
线程后续补充...