<!-- [if !mso]> <style> v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);} </style> <![endif]--><!-- [if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:PunctuationKerning/> <w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing> <w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery> <w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:Compatibility> <w:SpaceForUL/> <w:BalanceSingleByteDoubleByteWidth/> <w:DoNotLeaveBackslashAlone/> <w:ULTrailSpace/> <w:DoNotExpandShiftReturn/> <w:AdjustLineHeightInTable/> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:UseFELayout/> </w:Compatibility> <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel> </w:WordDocument> </xml><![endif]--><!-- [if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" LatentStyleCount="156"> </w:LatentStyles> </xml><![endif]--><!-- [if !mso]> <object classid="clsid:38481807-CA0E-42D2-BF39-B33AF135CC4D" id=ieooui> </object> <style> st1\:*{behavior:url(#ieooui) } </style> <![endif]--><!-- [if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:普通表格; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} </style> <![endif]-->
Java 多线程总结
线程的四种状态:
就绪Runable ——运行中Running ——阻塞Blocked ——死亡Dead( 结束)
线程的状态转换图
线程在一定条件下,状态会发生变化。线程变化的状态转换图如下:
1 、新建状态(New ):新创建了一个线程对象。
2 、就绪状态(Runnable ):线程对象创建后,其他线程调用了该对象的start() 方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU 的使用权。
3 、运行状态(Running ):就绪状态的线程获取了CPU ,执行程序代码。
4 、阻塞状态(Blocked ):阻塞状态是线程因为某种原因放弃CPU 使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait() 方法,JVM 会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM 会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep() 或join() 方法,或者发出了I/O 请求时,JVM 会把该线程置为阻塞状态。当sleep() 状态超时、join() 等待线程终止或者超时、或者I/O 处理完毕时,线程重新转入就绪状态。
5 、死亡状态(Dead ):线程执行完了或者因异常退出了run() 方法,该线程结束生命周期。
线程的调度
1 、调整线程优先级:Java 线程有优先级,优先级高的线程会获得较多的运行机会。
Java 线程的优先级用整数表示,取值范围是1~10 ,Thread 类有以下三个静态常量:
static int MAX_PRIORITY 线程可以具有的最高优先级,取值为10 。
static int MIN_PRIORITY 线程可以具有的最低优先级,取值为1 。
static int NORM_PRIORITY 分配给线程的默认优先级,取值为5 。
Thread 类的setPriority() 和getPriority() 方法分别用来设置和获取线程的优先级。
每个线程都有默认的优先级。主线程的默认优先级为Thread.NORM_PRIORITY 。
线程的优先级有继承关系,比如A 线程中创建了B 线程,那么B 将和A 具有相同的优先级。
JVM 提供了10 个线程优先级,但与常见的操作系统都不能很好的映射。如果希望程序能移植到各个操作系统中,应该仅仅使用Thread 类有以下三个静态常量作为优先级,这样能保证同样的优先级采用了同样的调度方式。
2 、线程睡眠:Thread.sleep(long millis) 方法,使线程转到阻塞状态。millis 参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable )状态。
3 、线程等待:Object 类中的wait() 方法,导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 唤醒方法。这个两个唤醒方法也是Object 类中的方法,行为等价于调用 wait(0) 一样。
4 、线程让步:Thread.yield() 方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。
5 、线程加入:join() 方法,等待其他线程终止。在当前线程中调用另一个线程的join() 方法,则当前线程转入阻塞状态,直到另一个线程运行结束,当前线程再由阻塞转为就绪状态。
6 、线程唤醒:Object 类中的notify() 方法,唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。 直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。类似的方法还有一个notifyAll() ,唤醒在此对象监视器上等待的所有线程。
JAVA 多线程实现的两种模型
区别与联系:
l Runnable 是 Thread 的接口,在大多数情况下 “ 推荐用接口的方式 ” 生成线程,因为接口可以实现多继承,况且 Runnable 只有一个 run 方法,很适合继承。
l
在使用
Thread
的时候只需要
new
一个实例出来,调用
start()
方法即可以启动一个线程。
Thread Test = new
Thread();
Test.start();
l 在使用 Runnable 的时候需要先 new 一个实现 Runnable 的类的实例,之后,创建线程时将线程与该实例关联(其本质是让该线程执行时调用该实例中的 run 方法 )。
l 扩展Thread 类实现
class MyThread extends Thread {
public MyThread (String threadName) {
super(threadName);
}
public void run() {
System.out.println(getName() + " 线程运行开始!");
for (int i = 0; i < 10; i++) {
System.out.println(i + " " + getName());
try {
sleep((int) Math.random() * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(getName() + " 线程运行结束!");
}
}
public class TestMyThread {
public static void main(String[] rags) {
System.out.println(Thread.currentThread().getName() + " 线程运行开始!");
new MyThread ("A").start();
new MyThread ("B").start();
System.out.println(Thread.currentThread().getName() + " 线程运行结束!");
}
}
运行结果:
main 线程运行开始!
main 线程运行结束!
A 线程运行开始!
0 A
1 A
B 线程运行开始!
2 A
0 B
3 A
4 A
1 B
5 A
6 A
7 A
8 A
9 A
A 线程运行结束!
2 B
3 B
4 B
5 B
6 B
7 B
8 B
9 B
B 线程运行结束!
说明:
程序启动运行main 时候,java 虚拟机启动一个进程,主线程main 在main() 调用时候被创建。随着调用MyThread 的两个对象的start 方法,另外两个线程也启动了,这样,整个应用就在多线程下运行。
在一个方法中调用Thread.currentThread().getName() 方法,可以获取当前线程的名字。在mian 方法中调用该方法,获取的是主线程的名字。
注意:start() 方法的调用后并不是立即执行多线程代码,而是使得该线程变为可运行态(Runnable ),什么时候运行是由操作系统决定的。从程序运行的结果可以发现,多线程程序是乱序执行。因此,只有乱序执行的代码才有必要设计为多线程。
Thread.sleep() 方法调用目的是不让当前线程独自霸占该进程所获取的CPU 资源,以留出一定时间给其他线程执行的机会。实际上所有的多线程代码执行顺序都是不确定的,每次执行的结果都是随机的。
l 实现java.lang.Runnable 接口
public class TestMyThread implements Runnable {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + " 线程运行开始!");
TestMyThread test = new TestMyThread ();
Thread thread1 = new Thread(test);
Thread thread2 = new Thread(test);
thread1.start();
thread2.start();
System.out.println(Thread.currentThread().getName() + " 线程运行结束!");
}
public void run() {
System.out.println(Thread.currentThread().getName() + " 线程运行开始!");
for (int i = 0; i < 10; i++) {
System.out.println(i + " " + Thread.currentThread().getName());
try {
Thread.sleep((int) Math.random() * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " 线程运行结束!");
}
}
运行结果:
main 线程运行开始!
Thread-0 线程运行开始!
main 线程运行结束!
0 Thread-0
Thread-1 线程运行开始!
0 Thread-1
1 Thread-1
1 Thread-0
2 Thread-0
2 Thread-1
3 Thread-0
3 Thread-1
4 Thread-0
4 Thread-1
5 Thread-0
6 Thread-0
5 Thread-1
7 Thread-0
8 Thread-0
6 Thread-1
9 Thread-0
7 Thread-1
Thread-0 线程运行结束!
8 Thread-1
9 Thread-1
Thread-1 线程运行结束!
说明:
TestMitiThread1 类通过实现Runnable 接口,使得该类有了多线程类的特征。run ()方法是多线程程序的一个约定。所有的多线程代码都在run 方法里面。Thread 类实际上也是实现了Runnable 接口的类。
在启动的多线程的时候,需要先通过Thread 类的构造方法Thread(Runnable target) 构造出对象,然后调用Thread 对象的start() 方法来运行多线程代码。
实际上所有的多线程代码都是通过运行Thread 的start() 方法来运行的。因此,不管是扩展Thread 类还是实现Runnable 接口来实现多线程,最终还是通过Thread 的对象的API 来控制线程的,熟悉Thread 类的API 是进行多线程编程的基础。
读解Thread 类API
构造方法摘要
Thread(Runnable target) 分配新的 Thread 对象。
Thread(String name) 分配新的 Thread 对象。
方法摘要
static Thread currentThread()
说明:返回对当前正在执行的线程对象的引用。
void start()
说明:使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
void stop()
说明:已过时, 该方法具有固有的不安全性。
void suspend()
说明:已过时。 该方法已经遭到反对,因为它具有固有的死锁倾向。
void resume()
说明:该方法已过时,它只与 suspend() 一起使用,但 suspend() 已经遭到反对,因为它具有死锁倾向。
static void sleep(long millis)
说明:在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。
static void sleep(long millis, int nanos)
说明:在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行)。
static void yield()
说明:线程让权,暂停当前正在执行的线程对象,并执行其他线程。
void interrupt() : 说明:中断线程。
void join() :
说明:等待其他线程终止。在当前线程中调用另一个线程的join() 方法,则当前线程转入阻塞状态,直到另一个线程运行结束,当前线程再由阻塞转为就绪状态。
void run() 说明:线程方法运行。
String toString()
说明:返回该线程的字符串表示形式,包括线程名称、优先级和线程组。

被折叠的 条评论
为什么被折叠?



