﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-java路，自己走-文章分类-java.thread</title><link>http://www.blogjava.net/syniii/category/47072.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 17 Nov 2010 08:02:31 GMT</lastBuildDate><pubDate>Wed, 17 Nov 2010 08:02:31 GMT</pubDate><ttl>60</ttl><item><title>java线程的几个概念和方法</title><link>http://www.blogjava.net/syniii/articles/338254.html</link><dc:creator>杨罗罗</dc:creator><author>杨罗罗</author><pubDate>Wed, 17 Nov 2010 07:08:00 GMT</pubDate><guid>http://www.blogjava.net/syniii/articles/338254.html</guid><wfw:comment>http://www.blogjava.net/syniii/comments/338254.html</wfw:comment><comments>http://www.blogjava.net/syniii/articles/338254.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/syniii/comments/commentRss/338254.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/syniii/services/trackbacks/338254.html</trackback:ping><description><![CDATA[<p><img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/syniii/tech_42b.jpg" width="450" height="409" /><br />
<br />
在Java中创建线程有两种方法：使用Thread类和使用Runnable接口。<br />
要注意的是Thread类也实现了Runnable接口，因此，从Thread类继承的类的实例也可以作为target传入这个构造方法。可通过这种方法实现多个线程的资源共享。</p>
<p><strong>线程的生命周期：<br />
</strong>新建状态：用new语句创建的线程对象处于新建状态，此时它和其它的java对象一样，仅仅在堆中被分配了内存 <br />
就绪状态：当一个线程创建了以后，其他的线程调用了它的start()方法，该线程就进入了就绪状态。处于这个状态的线程位于可运行池中，等待获得CPU的使用权 <br />
运行状态：处于这个状态的线程占用CPU,执行程序的代码 <br />
阻塞状态：当线程处于阻塞状态时，java虚拟机不会给线程分配CPU，直到线程重新进入就绪状态，它才有机会转到运行状态。 <br />
阻塞状态分为三种情况： <br />
1、 位于对象等待池中的阻塞状态：当线程运行时，如果执行了某个对象的wait()方法，java虚拟机就回把线程放到这个对象的等待池中 <br />
2、 位于对象锁中的阻塞状态，当线程处于运行状态时，试图获得某个对象的同步锁时，如果该对象的同步锁已经被其他的线程占用，JVM就会把这个线程放到这个对象的琐池中。 <br />
3、 其它的阻塞状态：当前线程执行了sleep()方法，或者调用了其它线程的join()方法，或者发出了I/O请求时，就会进入这个状态中。<br />
<br />
一、创建并运行线程<br />
&nbsp;&nbsp;&nbsp; 当调用start方法后，线程开始执行run方法中的代码。线程进入运行状态。可以通过Thread类的isAlive方法来判断线程是否处于运行状态。当线程处于运行状态时，isAlive返回true，当isAlive返回false时，可能线程处于等待状态，也可能处于停止状态。</p>
<p>二、挂起和唤醒线程<br />
一但线程开始执行run方法，就会一直到这个run方法执行完成这个线程才退出。但在线程执行的过程中，可以通过两个方法使线程暂时停止执行。这两个方法是suspend和sleep。在使用suspend挂起线程后，可以通过resume方法唤醒线程。而使用sleep使线程休眠后，只能在设定的时间后使线程处于就绪状态（在线程休眠结束后，线程不一定会马上执行，只是进入了就绪状态，等待着系统进行调度）。<br />
虽然suspend和resume可以很方便地使线程挂起和唤醒，但由于使用这两个方法可能会造成一些不可预料的事情发生，因此，这两个方法被标识为deprecated(抗议)标记，这表明在以后的jdk版本中这两个方法可能被删除，所以尽量不要使用这两个方法来操作线程。下面的代码演示了sleep、suspend和resume三个方法的使用。</p>
<p>三、终止线程的三种方法<br />
有三种方法可以使终止线程。<br />
1.&nbsp; 使用退出标志，使线程正常退出，也就是当run方法完成后线程终止。<br />
2.&nbsp; 使用stop方法强行终止线程（这个方法不推荐使用，因为stop和suspend、resume一样，也可能发生不可预料的结果）。<br />
3.&nbsp; 使用interrupt方法中断线程。<br />
<br />
<strong>线程的几个方法：<br />
</strong>join()：等待此线程死亡后再继续，可使异步线程变为同步线程<br />
interrupt()：中断线程，被中断线程会抛InterruptedException<br />
<br />
线程通信：wait(),notify()&nbsp;&nbsp;&nbsp;- 典型应用：放取鸡蛋<br />
wait() 等待获取锁：<span style="widows: 2; text-transform: none; text-indent: 0px; border-collapse: separate; font: medium Simsun; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(0,0,0); word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"><span style="line-height: 22px; font-family: Arial; font-size: 14px" class="Apple-style-span"></p>
<pre style="padding-bottom: 0px; line-height: 22px; margin: 0px; padding-left: 0px; padding-right: 0px; zoom: 1; font-family: Arial; word-wrap: break-word; white-space: pre-wrap; font-size: 14px; font-weight: normal; padding-top: 0px">表示等待获取某个锁</pre>
<p></span></span>执行了该方法的线程<span style="color: red">释放对象的锁</span>，JVM会把该线程放到<span style="color: red">对象的等待池</span>中。该线程等待其它线程唤醒 <br />
notify() 执行该方法的线程唤醒在对象的等待池中等待的一个线程，JVM从对象的等待池中随机选择一个线程，把它转到对象的锁池中。使线程由阻塞队列进入就绪状态<br />
<br />
sleep()：让当前正在执行的线程休眠，有一个用法可以代替yield函数——sleep(0)<br />
<span style="widows: 2; text-transform: none; text-indent: 0px; border-collapse: separate; font: medium Simsun; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(0,0,0); word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"><span style="line-height: 19px; text-indent: 29px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px" class="Apple-style-span">yield()</span></span>：暂停当前正在执行的线程对象，并执行其他线程。也就是交出CPU一段时间<br />
<br />
sleep和yield区别：<br />
1、sleep()方法会给其他线程运行的机会，而不考虑其他线程的优先级，因此会给较低线程一个运行的机会；yield()方法只会给相同优先级或者更高优先级的线程一个运行的机会。 <br />
2、当线程执行了<span style="color: red">sleep(long millis)</span>方法后，<span style="color: red">将转到阻塞状态</span>，参数millis指定睡眠时间；当线程执行了<span style="color: red">yield()方法后，将转到就绪状态</span>。 <br />
3、sleep()方法声明抛出InterruptedException异常，而yield()方法没有声明抛出任何异常 <br />
4、sleep()方法比yield()方法具有更好的移植性 <br />
<br />
如果希望明确地让一个线程给另外一个线程运行的机会，可以采取以下的办法之一：<br />
1、 调整各个线程的优先级 <br />
2、 让处于运行状态的线程调用Thread.sleep()方法 <br />
3、 让处于运行状态的线程调用Thread.yield()方法 <br />
4、 让处于运行状态的线程调用另一个线程的join()方法<br />
<br />
</p>
<div id="blog_text" class="cnt">首先，<strong style="background-color: rgb(255,204,0)">wait()和notify(),notifyAll()是Object类的方法，sleep()和yield()是Thread类的方法</strong><span style="background-color: rgb(255,204,0)">。</span><br />
<br />
(1).常用的wait方法有<font color="#0000ff"><strong>wait()</strong></font>和<font color="#0000ff"><strong>wait(long </strong><strong>timeout</strong></font><font color="#0000ff"><strong>)</strong></font>:<br />
&nbsp;&nbsp;&nbsp; void wait() 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前，导致当前线程等待。 <br />
&nbsp;&nbsp;&nbsp; void wait(long timeout) 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法，或者超过指定的时间量前，导致当前线程等待。<br />
&nbsp;&nbsp;&nbsp; <strong style="background-color: rgb(255,204,0)">wait()后，线程会释放掉它所占有的&#8220;锁标志&#8221;</strong>，从而使线程所在对象中的其它synchronized数据可被别的线程使用。<br />
&nbsp;&nbsp;&nbsp; wait()和notify()因为会对对象的&#8220;锁标志&#8221;进行操作，所以它们必须在synchronized函数或synchronized　 block中进行调用。如果在non-synchronized函数或non-synchronized　block中进行调用，虽然能编译通过，但在运 行时会发生IllegalMonitorStateException的异常。<br />
<br />
(2).<font color="#0000ff"><strong>Thread.sleep(long millis),必须带有一个时间参数</strong></font>。<br />
&nbsp;&nbsp;&nbsp; sleep(long)使当前线程进入停滞状态，所以执行sleep()的线程在指定的时间内肯定不会被执行；<br />
&nbsp;&nbsp;&nbsp; sleep(long)可使优先级低的线程得到执行的机会，当然也可以让同优先级和高优先级的线程有执行的机会；<br />
&nbsp;&nbsp;&nbsp; sleep(long)是不会释放锁标志的。<br />
<br />
(3).<font color="#0000ff"><strong>yield()没有参数。</strong></font><br />
&nbsp;&nbsp;&nbsp; sleep 方法使当前运行中的线程睡眼一段时间，进入不可运行状态，这段时间的长短是由程序设定的，<span style="background-color: rgb(255,204,0)">yield 方法使当前线程让出CPU占有权，但让出的时间是不可设定的</span>。<br />
&nbsp;&nbsp;&nbsp; <font color="#800000"><strong>yield()也不会释放锁标志。</strong></font><br />
<br />
&nbsp;&nbsp;&nbsp; 实际上，yield()方法对应了如下操作： 先检测当前是否有相同优先级的线程处于同可运行状态，如有，则把 CPU 的占有权交给此线程，否则继续运行原来的线程。所以yield()方法称为&#8220;退让&#8221;，它把运行机会让给了同等优先级的其他线程。<br />
<br />
&nbsp;&nbsp;&nbsp; sleep方法允许较低优先级的线程获得运行机会，但<span style="background-color: rgb(255,204,0)">yield()方法执行时，当前线程仍处在可运行状态，所以不可能让出较低优先级的线程些时获得CPU占有权</span>。 在一个运行系统中，如果较高优先级的线程没有调用 sleep 方法，又没有受到 I/O阻塞，那么较低优先级线程只能等待所有较高优先级的线程运行结束，才有机会运行。<br />
<br />
&nbsp;&nbsp;&nbsp; yield()只是使当前线程重新回到可执行状态，所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。所以yield()只能使同优先级的线程有执行的机会。</div>
<p><strong>volitile 语义：<br />
</strong>volatile相当于synchronized的弱实现，也就是说volatile实现了类似synchronized的语义，却又没有锁机制。它确保对volatile字段的更新以可预见的方式告知其他的线程。<br />
volatile包含以下语义：<br />
（1）Java 存储模型不会对valatile指令的操作进行重排序：这个保证对volatile变量的操作时按照指令的出现顺序执行的。<br />
（2）volatile变量不会被缓存在寄存器中（只有拥有线程可见）或者其他对CPU不可见的地方，每次总是从主存中读取volatile变量的结果。也就是说对于volatile变量的修改，其它线程总是可见的，并且不是使用自己线程栈内部的变量。也就是在happens-before法则中，对一个valatile变量的写操作后，其后的任何读操作理解可见此写操作的结果。<br />
尽管volatile变量的特性不错，但是volatile并不能保证线程安全的，也就是说volatile字段的操作不是原子性的，volatile变量只能保证可见性（一个线程修改后其它线程能够理解看到此变化后的结果），要想保证原子性，目前为止只能加锁！<br />
<br />
<strong>数据同步：<br />
</strong></p>
线程同步的特征： <br />
1、 如果一个同步代码块和非同步代码块同时操作共享资源，仍然会造成对共享资源的竞争。因为当一个线程执行一个对象的同步代码块时，其他的线程仍然可以执行对象的非同步代码块。（所谓的线程之间保持同步，是指不同的线程在执行同一个对象的同步代码块时，因为要获得对象的同步锁而互相牵制） <br />
2、 每个对象都有唯一的同步锁 <br />
3、 在静态方法前面可以使用synchronized修饰符。 <br />
4、 当一个线程开始执行同步代码块时，并不意味着必须以不间断的方式运行，进入同步代码块的线程可以执行Thread.sleep()或者执行Thread.yield()方法，此时它并不释放对象锁，只是把运行的机会让给其他的线程。 <br />
5、 Synchronized声明不会被继承，如果一个用synchronized修饰的方法被子类覆盖，那么子类中这个方法不在保持同步，除非用synchronized修饰。 
<img src ="http://www.blogjava.net/syniii/aggbug/338254.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/syniii/" target="_blank">杨罗罗</a> 2010-11-17 15:08 <a href="http://www.blogjava.net/syniii/articles/338254.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>