一.什么是多线程java
在学习多进程以前得先明白两个概念:
程序员
进程:每一个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程,进程是资源分配的最小单位;安全
线程:同一类线程共享代码和数据空间,每一个线程有独立的运行栈和程序计数器(PC),线程切换开销小,线程是cpu调度的最小单位;多线程
线程和进程同样分为五个阶段:建立、就绪、运行、阻塞、终止。函数
多进程是指操做系统能同时运行多个任务(程序)。学习
多线程是指在同一程序中有多个顺序流在执行。 spa
多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。操作系统
这里定义和线程相关的另外一个术语 - 进程:一个进程包括由操做系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个 进程一直运行,直到全部的非守护线程都结束运行后才能结束。多线程能知足程序员编写高效率的程序来达到充分利用 CPU 的目的。线程
二.怎样开启多线程对象
在java中要想实现多线程,有两种手段,一种是继承Thread类,另一种是实现Runable接口。
实现Runable接口:
实现 Runnable,一个类只须要执行一个方法调用 run(),在建立一个实现 Runnable 接口的类以后,你能够在类中实例化一个线程对象,新线程建立以后,你调用它 的 start() 方法它才会运行。
继承Thread类:
建立一个线程的第二种方法是建立一个新的类,该类继承 Thread 类,而后建立一个该类的实例。继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须 调用 start() 方法才能执行。
3、Thread和Runnable的区别
若是一个类继承Thread,则不适合资源共享。可是若是实现了Runable接口的话,则很容易的实现资源共享。
总结:
实现Runnable接口比继承Thread类所具备的优点:
1):适合多个相同的程序代码的线程去处理同一个资源
2):能够避免java中的单继承的限制
3):增长程序的健壮性,代码能够被多个线程共享,代码和数据独立
4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
四.线程状态的转换
建立:新建立了一个线程对象;
就绪状态(Runnable):线程对象建立后,其余线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获 CPU的使用权。
运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
阻塞状态(Blocked):阻塞状态是线程由于某种缘由放弃CPU使用权,暂时中止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的状况分三种:
等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。(wait会释放持有的锁)
同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
其余阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、 或者I/O处理完毕时,线程从新转入就绪状态。(注意,sleep是不会释放持有的锁)
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
五.经常使用方法
sleep(long millis): 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
join():指等待t线程终止。
yield():暂停当前正在执行的线程对象,并执行其余线程,在大多数状况下,yield()将致使线程从运行状态转到可运行状态,但有可能没有效果
sleep()和yield()的区别):sleep()使当前线程进入停滞状态,因此执行sleep()的线程在指定的时间内确定不会被执行;yield()只是使当前线程从新回到可执行状态,因此执行yield()的线程有可能在进入到可执行状态后立刻又被执行。
sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其余线程,可是对象的锁依然保持,所以休眠时间结束后会自动恢复。wait()是Object类的方法,调用对象的wait()方法致使当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),若是线程从新得到对象的锁就能够进入就绪状态。
sleep()睡眠时,保持对象锁,仍然占有该锁;
wait()睡眠时,释放对象锁。
notify(): 通知一个线程继续运行,得到锁标记。
六.线程安全
通常理解为线程同步,线程同步的目的是为了保护多个线程反问一个资源时对资源的破坏,线程同步方法是经过锁来实现,每一个对象都有切仅有一个锁,这个锁与一个 特定的对象关联,线程一旦获取了对象锁,其余访问该对象的线程就没法再访问该对象的其余非同步方法,当多个线程等待一个对象锁时,没有获取到锁的线程将发生阻 塞,死锁是线程间相互等待锁锁形成的,在实际中发生的几率很是的小。真让你写个死锁程序,不必定好使,呵呵。可是,一旦程序发生死锁,程序将死掉。
保持线程同步的方法通常就是加锁,如synchronized关键字。synchronized关键字能够做为函数的修饰符,也可做为函数内的语句,也就是平时说的同步方法和同步 语句块。若是再细的分类,synchronized可做用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。只要一个线程访问了其中 的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法。