.Net转Java自学之路—基础巩固篇十二(多线程)
多线程:
JVM的启动是一个多线程程序;其中有一个程序负责从主函数开始,并控制程序的运行流程;同事为了提高效率,还启动了另一个控制单元,专门负责堆内存垃圾的回收。
负责执行征程程序代码的线程,称为主线程。
该线程执行的代码都存放于主函数中。
负责垃圾回收的线程,该线程代码在finalize中。
进程:当前正在执行的程序;代表一个应用程序在内存中的执行区域。
线程:是进程中的一个执行控制单元,执行路径。
一个进程中至少有一个线程在负责控制程序的执行。
一个进程中如果只有一个执行路径,那么这个程序称为单线程。
一个进程中有多个执行路径时,这个程序称为多线程。
特点:提高效率
定义:线程的定义用 Thread 类。
创建方式:
1、创建一个 Thread 子类,并覆盖 Thread 中的 run() 方法。
覆盖 run() 方法是为了让该线程执行自定义的代码段;这时 new 一个该子类的对象,其实就是在创建一个线程。
2、创建 Thread 对象。
3、实现 Runnable 接口。
在内存中的表现形式:
1、堆内存中产生一个对象。
2、需要调用底层资源,去创建执行路径。
如果直接调用该对象的 run() 方法,这时,底层资源并没有完成线程的创建和执行,仅仅是简单的对象调用方法的过程,这时,执行控制流程的只有主线程。
开启线程:
调用 Thread 类中的 start() 方法。
作用:1、开启线程。2、调用线程的 run() 方法。
特性:
随机性。
为了对各线程的标识,有一个默认的名称,用 getName() 获取,名称编号从0开始;例:Thread-0、Thread-1......
重新定义线程名称:
1、线程对象.setName(strName)。
2、Thread(strName) 构造函数定义线程名称。
通过 currentThread() 返回当前线程对象,该方法为静态。
线程:
1、start() 开始
2、run() 运行
3、sleep(time) 睡眠
4、wait()/wait(time) 等待
5、notify() 唤醒
6、临时阻塞特点:该线程具备执行资格,但不具备执行权。
线程安全问题:
因为线程的随机性,有可能会导致多线程在操作系统时发生数据错误的情况产生。
产生原因:
当线程中的多条代码在操作同一个共享数据时,一个线程将部分代码执行完毕,还没有继续其他代码时,被另一个线程获取CPU执行权,这时,共享数据操作就有可能出现数据错误。
简单来说,多条操作共享数据的代码被多个线程分开执行造成的。
涉及的内容:
1、共享数据。2、是否被多条语句操作。
这也是判断多线程程序是否存在安全隐患的依据。
解决方式:
Java 的同步机制。
解决原理:
让多条操作共享数据的代码在某一时间段,被一个线程执行完,在执行过程中其他线程不能进行该代码段的操作。
同步格式:
synchronized(对象) { 同步代码段 }
优点:解决了多线程的安全问题。
弊端:效率降低。
前提:
1、必须是俩个/俩个以上的线程在执行同一个同步代码段。
2、必须保证多个线程使用的同一锁。
已加上同步,但安全问题依然存在,按照以上俩个前提排查。
如同步代码段提取成一个函数,那么需要该函数用 synchronized 修饰下即可。
同步代码段和同步函数的区别:
代码段使用的锁可以是人员对象,而同步函数的锁是固定对象 this。So、一般建议用同步代码段,当然,如果对象可以使用 this,那么可以简化同步函数的形式。