`
158067568
  • 浏览: 329285 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java 多线程 高手进阶 一

    博客分类:
  • j2se
阅读更多

多线程菜鸟进阶 一

QQ158067568

作者:Legend

本文将进入多线程的学习中。在开始之前,需要明白线程的概念。

线程不是进程

作为有一定开发经验的程序员来说,在java中实现多线程是一件很容易的事情,你只需要将你的类继承Thread类或者实现Runnable接口就可以。其实线程完全可以理解为一个任务。可以同时运行多个任务的程序,就成为多线程程序。

然而线程并非进程。进程包括线程,每一个进程都拥有一套自己的变量,而线程间则共享这套变量。从而带来了很多风险,比如最典型的脏数据。这些以后会讨论。

线程状态

java中,线程被定义成有6中状态:

NEW

至今尚未启动的线程处于这种状态。 即刚刚new出来的Thread,但是还未调用start()方法。

RUNNABLE

正在 Java 虚拟机中执行的线程处于这种状态。 该状态是调用了start()方法后的状态,出于该状态的线程不一定是正在运行的,他有线程调度器来决定是否运行。

BLOCKED

受阻塞并等待某个监视器锁的线程处于这种状态。 阻塞与等待不同,阻塞通常是得不到所需要的资源而被迫停下来等待。

WAITING

无限期地等待另一个线程来执行某一特定操作的线程处于这种状态。

TIMED_WAITING

等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态。

TERMINATED

已退出的线程处于这种状态。有两种情况会让线程退出,其一是run方法中的任务执行完成,其二是线程执行时出现异常。

java的线程状态只有如上6中,他们以enum形式被定义在Thread.State中。这里要说一下等待状态,有很多方式能够让线程进入等待状态,比如调用join()方法。

join()

对于这个方法,还是要特别的强调一下。在api中的解释如下:Blocks the current Thread (Thread.currentThread()) until the receiver finishes its execution and dies.翻译过来就是:阻塞当前线程,然后让接受者完成任务之后,当前线程才开始继续执行任务。

但是如果接受者在被调用了join方法后,有被调用了interrupt()方法,则会抛出java.lang.InterruptedException异常。可以参考代码ThreadDemo01

 

package cn.edu.heut.zcl;

 

public class ThreadDemo01 {

 

         public static void main(String[] args) {

                   TA ta = new TA();

                   ta.start();

                   try {

                            ta.join();

                   } catch (InterruptedException e) {

                            e.printStackTrace();

                   }

                   int i = 0;

                   while ((i++) < 10) {

                            System.out.println("-------");

                            try {

                                     Thread.sleep(100);

                            } catch (InterruptedException e) {

                                     e.printStackTrace();

                            }

                   }

         }

}

class TA extends Thread {

 

         @Override

         public void run() {

                   super.run();

                   int i = 0;

                   while ((i++) < 40) {

                            System.out.println("---->A");

                            if (i == 10) {

                                     Thread.currentThread().interrupt();

                            }


                            try {

                                     Thread.sleep(100);

                            } catch (InterruptedException e) {

                                     // TODO Auto-generated catch block

                                     e.printStackTrace();

                            }

                   }

         }

}


 

 

 

 

记住:join()方法是将当前线程阻塞

interrupt()与中断线程

开发时常常需要用到中断线程,在早期的java版本中,有stop()等方法用来控制线程生死,当时这些方法现在已经废弃,具体愿意以后会谈,同时亦可以参考sun的一片文章《Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated?》网址如下:

http://download.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html

当然,jdk还是为我们提供了强化终止线程的方法。然而,interrupt方法只是可以用来请求终止线程。当对一个线程调用interrupt方法之后,线程的中断状态将被置位。每一个线程都具有一个中断状态,他是一个boolean标志。在实现自己的线程时,应该实时检查该标志,以判断线程是否被中断。

可以通过Thread.currentThread()方法得到当前线程,然后通过is isInterrupted()方法,来查看中断状态。通常如下实现:

while (!Thread.currentThread().isInterrupted() && 。。。) {}

如果你已经运行了ThreadDemo01代码,那么你会发现,在TA类中如下代码处:

if (i == 10) {

                                     Thread.currentThread().interrupt();

                            }

 

 

 

 

将会抛出异常java.lang.InterruptedException。这个是由于在TA线程中调用了interrupt方法后,中断状态已经置为,如果此时再调用sleep等阻塞方法后,该线程不会休眠,想法,他将抛出中断异常并且将中断状态清楚。所以如下代码是不会让线程TB停止。CopyOfThreadDemo02

 

package cn.edu.heut.zcl;

 

public class CopyOfThreadDemo02 {

 

         public static void main(String[] args) {

                   TB ta = new TB();

                   ta.start();

                   int i = 0;

                   while ((i++) < 10) {

                            System.out.println("-------");

                            try {

                                     Thread.sleep(100);

                            } catch (InterruptedException e) {

                                     e.printStackTrace();

                            }

                   }

         }

}

 

class TB extends Thread {

 

         @Override

         public void run() {

                   super.run();

                   int i = 0;

                   while (!Thread.currentThread().isInterrupted() && (i++) < 40) {

                            System.out.println("---->A");

                            if(i == 4) Thread.currentThread().interrupt();//在sleep之前调用,将不能终止线程

                            try {

                                     Thread.sleep(100);

                            } catch (InterruptedException e) {

                                     // TODO Auto-generated catch block

                                     e.printStackTrace();

                            }

                            //if(i == 4) Thread.currentThread().interrupt();//在sleep之后调用,将能终止线程

                   }

         }

}

 

 

 

 

你可以自己试一试,运行如上代码,不能中断TB线程。但是如果在sleep之后调用interrupt,则会中断线程。

interrupted()isInterrupted()

这两个方法看上去很像,作用也相似可以通过下表来比较两种异同。

 

是否是static

返回值

不同

interrupted

当前的中断状态

调用后改变中断状态

isInterrupted

不改变

 

线程属性----线程优先级

 

谈优先级可能并不陌生,在java中,每一个线程都有一个优先级。默认情况下,一个线程的优先级直接继承自他的父类。sunjava的优先级分成10级,1表示最小优先级,10表示最高优先级。同时jdk中还定义了3个常量MIN_PRIORITY(1)MAX_PRIORITY(10)NORM_PRIORITY(5)

线程的优先级是依赖与平台的,windows中有7个优先级。而在Linux中,java虚拟机将线程的优先级忽略,即所有线程的优先级都一样。所以在编写程序是,尽量不要依赖于优先级。

setPriority()方法,顾名思义就是设置优先级的。

yield()

yield的中文意思是:屈服。其实理解成让步更加准确。调用该方法,将导致当前执行线程出于让步状态。如果此时有其他线程一起来抢夺cpu资源,那么只要这个抢夺的线程的优先级不低于调用线程。则抢夺线程将会被调用。

线程属性----守护线程

守护线程的用途就是为其他线程提供服务。当被服务者死亡后,其也就没有存在的价值,也就跟着去死了。设置守护线程很简单:

setDaemontrue

只需一步,轻松搞定。在使用守护线程时需要记住,永远不要去访问固有资源,如文件、数据库等。以为你不知道什么时候守护线程会结束。

可以参考DeamonDemo

 

package cn.edu.heut.zcl;

/**

 * 演示守护线程

 * @author Legend

 *

 */

public class DeamonDemo {

         

         public static void main(String[] args){

                   DemonRunnable dr = new DemonRunnable();

                   dr.setDaemon(true);//设置为守护线程

                   dr.start();

                   int i = 0 ;

                   while((i++)<10){

                            try {

                                     Thread.sleep(500);

                                     System.out.println(i);

                            } catch (InterruptedException e) {

                                     e.printStackTrace();

                            }

                   }

         }

         

         private static class DemonRunnable extends Thread{

                   @Override

                   public void run() {

                            super.run();

                            while(true){

                                     System.out.println("------");

                                     try {

                                               Thread.sleep(100);

                                     } catch (InterruptedException e) {

                                               e.printStackTrace();

                                     }

                            }

                   }

         }

}

 

 

 

 

 

 

 

分享到:
评论
13 楼 feng_201 2011-03-16  
谢谢    学习了....
12 楼 ouchxp 2011-03-15  
我晕 LZ标题党. 我是看了"高手进阶"才进来的.
结果进来变成 "菜鸟进阶" 了  我吐...............
11 楼 fatdolphin 2011-03-14  
还是不太明白wait和join的区别,虽说join是为了等待资源而停下来,而wait是无限期堵塞,但是调用join和wait的线程被唤醒有什么区别呢。如果notifyall被调用,那之前调用wait的线程被唤醒,调用join的线程呢?是被唤醒还是继续堵塞中
10 楼 gp00142003 2011-03-14  
进程就像电源插线板,线程就是插板上面的一个个插座。
9 楼 sunnyhui2010 2011-03-14  
学习了一些线程相关的细节,谢了~
8 楼 vigorsoft 2011-03-14  
感谢,学习了。
7 楼 shichuanliujie 2011-03-14  
二胖学习ing。。。
6 楼 libo_591 2011-03-14  
感谢楼主,收获不小
5 楼 xuwenbo 2011-03-14  
赞一个,楼主继续...正好学习学习线程相关
4 楼 huzorro 2011-03-13  
建议看看1.6的多线程特性
3 楼 wqq686 2011-03-13  
<div class="quote_title">158067568 写道</div>
<div class="quote_div">
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small;"><span>作为有一定开发经验的程序员来说,在</span><span lang="EN-US"><span style="font-family: Times New Roman;">java</span></span><span>中实现多线程是一件很容易的事情,你只需要将你的类继承</span><span lang="EN-US"><span style="font-family: Times New Roman;">Thread</span></span><span>类或者实现</span><span lang="EN-US"><span style="font-family: Times New Roman;">Runnable</span></span><span>接口就可以。<strong>其实线程完全可以理解为一个任务。</strong>可以同时运行多个任务的程序,就成为多线程程序。</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span><span style="font-size: small;"><span style="color: #ff0000;">然而线程并非进程。<strong>进程包括线程,每一个进程都拥有一套自己的变量,而线程间则共享这套变量。</strong></span>从而带来了很多风险,比如最典型的脏数据。这些以后会讨论。</span></span></p>
</div>
<p>我的理解,进程(Process)与线程(Thread)的区别,是从哪个角度来看的问题,从JAVA的角度,没有进程、线程之分,都是Thread。原因:</p>
<p><a href="http://www.iteye.com/forums/39/topics/954765/java/lang/Thread.html#currentThread()"><strong><span style="font-family: Courier New;">currentThread</span></strong></a><span style="font-family: Courier New;">()</span> Returns a reference to the currently executing thread object.</p>
<p>public class Thread implements Runnable</p>
<p>启动一个JAVA进程,不论在哪里调用Thread.<a href="http://www.iteye.com/forums/39/topics/954765/java/lang/Thread.html#currentThread()"><strong><span style="font-family: Courier New;">currentThread</span></strong></a>()返回的都是当前Thread;</p>
<p>从操作系统的角度来说的,操作系统会区分这个是JAVA进程、那个是IE进程。</p>
<p>从根本上来说,进程与线程的区别在于是否有共享内存空间,以及共享了多少内存空间。对于进程和线程,操作系统的内核不同,可能会有不同的处理方式,比如,Windows和Linux在实现进程和线程就有很大的差异,对于windows来说创建进程比线程开销大,而对于Linux来说两者没有本质区别。</p>
<p><a href="http://stackoverflow.com/questions/807506/threads-vs-processes-in-linux">http://stackoverflow.com/questions/807506/threads-vs-processes-in-linux</a></p>
2 楼 xt19c 2011-03-12  
感谢楼主~继续出进阶二
1 楼 yehengxy 2011-03-12  
感谢楼主 我也学习了

相关推荐

    Android高手进阶教程

    《Android高手进阶教程》是一本专为已经具备Android基础知识并渴望进一步提升技能的开发者设计的教程。本书深入探讨了Android开发的高级概念和技术,旨在帮助读者从技术层面跨越到专家水平。 首先,我们来了解一下...

    Android高手进阶指南

    《Android高手进阶指南》是一本专为已经具备一定Android基础的开发者准备的深度学习资料。这本书涵盖了Android开发中的高级主题和技术,旨在帮助读者提升在Android领域的专业技能,成为真正的技术专家。 首先,本书...

    Android高手进阶教程pdf

    《Android高手进阶教程》是一本专为已经具备一定Android基础知识的学习者设计的教程,旨在帮助读者提升在Android开发领域的专业技能。这本书采用中文撰写,易于理解和学习,内容覆盖了Android开发的诸多重要方面。 ...

    java语言程序设计基础篇+进阶篇源码

    - **多线程**:Java提供了Thread类和Runnable接口来实现并发编程,理解线程的创建、同步和通信对于处理多任务至关重要。 - **反射机制**:反射允许程序在运行时动态访问类的信息,创建和操作对象,是Java强大的...

    Java进阶高手课-深入浅出Java网络编程

    在Java中,多线程是实现并发处理的关键,特别是在网络编程中,通常一个服务器需要同时处理多个客户端的请求。Java提供了Thread类和Runnable接口来支持多线程编程,理解如何创建、管理线程以及避免线程安全问题至关...

    java整理的一些资料

    "想成为Java高手的25个学习目标.doc" 提供了一个详细的进阶路径,可能包括深入理解JVM(Java虚拟机)、异常处理、集合框架、反射机制、网络编程、I/O流、设计模式等内容。这些是成为一名优秀Java开发者必须掌握的...

    Java进阶高手课-Spring精讲精练

    在本课程"Java进阶高手课-Spring精讲精练"中,你将深入学习Java技术和Spring框架,提升你的编程技能并掌握高级概念。...通过学习,你将能够自信地应对复杂的编程挑战,成为一名真正的Java进阶高手。

    Java 进阶之路(黑夜版)

    - 多线程原理与实践 - 同步与锁机制 - 并发工具类详解 - 线程池的设计与使用 3. **Java虚拟机(JVM)**: - 内存区域与垃圾回收机制 - 类加载机制 - 性能调优技巧 4. **Java企业级开发**: - 开发、构建与...

    java入门与提高——一个成就java高手的教程

    12. **多线程**:学习如何创建和管理线程,理解线程同步机制,如synchronized关键字和wait/notify方法。 四、输入/输出(I/O) 13. **流的概念**:了解字节流和字符流,以及如何使用FileReader、FileWriter、...

    Java程序员高手文章集+(PDF)源码整理

    【Java程序员高手文章集+(PDF)源码整理】这一资源主要针对的是Java编程语言的学习与实践,特别是对于希望成为Java编程高手的程序员。这个压缩包包含了一整套精选的Java技术文章,以及相关的源码整理,是提升Java技能...

    java高手的文章合集

    总之,“java高手的文章合集”是一个全面涵盖Java基础知识与进阶技术的资源,无论你是初学者还是有经验的开发者,都能从中找到提升自我、深入理解Java的机会。通过系统学习和实践,你将离Java高手的目标更近一步。

    JAVA高手真经(基础篇)

    《JAVA高手真经(基础篇)》是一本深入浅出的JAVA编程学习指南,它针对初学者和进阶者提供了全面而扎实的JAVA基础知识。这本书的内容涵盖了JAVA语言的核心概念、语法以及开发实践中不可或缺的技巧,旨在帮助读者快速...

    高级爬虫进阶:HtmlUnit+多线线程+消息队列快速抓取大量信息数据

    高效的java爬虫,内附代码 sql数据表 ,main方法启动。jdk1.8. 有htmlunit的各种获取标签的方法。避免了jsoup无法抓取js代码生成的数据内容的弊端。避免了client无法一次性获取大量信息的弊端。有能获取静态页面形成...

    Java5.0Tiger程序高手秘笈PDF.rar

    《Java 5.0 Tiger 程序高手秘笈》是一本专为Java程序员设计的进阶学习资料,旨在帮助读者深入理解Java 5.0(也被称为Tiger)版本的新特性和高级编程技巧。Java 5.0是Java发展历程中的一个重要里程碑,引入了许多关键...

    Java高手真经(应用框架卷):Java+Web核心框架电子书

    此外,还可能涉及异常处理、集合框架、IO流、多线程等进阶主题,这些都是Java开发的基础,对于理解和使用Web框架至关重要。 二、Web开发环境 书籍可能会介绍如何配置开发环境,如安装JDK、设置环境变量、使用集成...

    java学习类网站,让你有菜鸟变高手

    3. **Java多线程编程** - **网址**:http://www.javacats.com/US/articles/MultiThreading.html - **内容介绍**:深入探讨Java中的多线程编程技术,包括线程创建、同步机制等内容。 #### 高级应用技术 1. **...

    Java进阶高手课-并发编程透彻理解

    总之,"Java进阶高手课-并发编程透彻理解"涵盖了Java并发编程的方方面面,从基础到高级,从理论到实践,旨在帮助学员建立起完整的并发编程知识体系,提升其在多线程环境下的编程技能。通过学习,学员不仅能够熟练...

Global site tag (gtag.js) - Google Analytics