什么是线程?什么是守护线程?
http://itmian.com/2011/05/11/java%e9%9d%a2%e8%af%95%e9%a2%98-%e5%a4%9a%e7%ba%bf%e7%a8%8b/
?
Java程序员面试中的多线程问题:
http://sd.csdn.net/a/20120528/2806046.html
?
?
1、线程:
?? 一般我们开发的程序都是只有一个主线程的,即MAIN()函数开始,但是在一些特别的场合下,比如服务器接受命令的过程,可能需要同时处理多个客户端发送的命令,这时就需要征对每个客户建立一个线程 。这样建立多线程程序,多线程可以使得在同一时间间隔内,执行多个指令,以至于多个逻辑处理并发的运行。
?? 在JAVA中有二种方法可以定义一个线程:Runnable接口与Thread类,最终都是由Thread类的 start()方法启动线程,而真正执行的命令在run()方法中 ,另外线程有几种状态:执行,终止,休眠,挂起等。在某种条件下各个状态之间可以互相转换。
?
一个线程结束的标志是:run()方法结束。
?一个锁被释放的标志是:synchronized块或方法结束
值得注意的是:线程的在被激活后不一定马上就运行,而是进入到可运行线程的队列中。
2、进程和线程的区别
?? 通俗一点说,进程就是程序的一次执行,而线程可以理解为进程中的执行的一段程序片段。
?? 用一点文词说就是,每个进程都有独立的数据空间 (进程上下文);而线程可以看成是轻量级的进程。
?? 一般来讲(不使用特 殊技术),同一进程所产生的线程共享同一块内存空间 。
?? 同一进程中的两段代码是不可能同时执行的,除非引入线程。
?? 线程是属于进程的,当进程退出时该进程所产生的线程都会被强制退出并清除 。
?? 线程占用的资源要少于进程所占用的资源。
?? 进程和线程都可以有优先级。
?? 在线程系统中进程也是一个线程。可以将进程理解为一个程序的第一个线程。
?? 多进程-----在操作系统中,能同时运行多个任务(程序)。
?? 多线程-----在同一应用程序中,有多个顺序流同时执行。
????
3、两种线程模型
??
?
4、实现Runnable接口相对于继承Thread类来说,有如下显著的好处:
(1)适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码,数据有效的分离,较好地体现了面向对象的设计思想。
(2)可以避免由于Java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnable接口的方式了。
(3)有利于程序的健壮性,代码能够被多个线程共享,代码与数据是独立的 。当多个线程的执行代码来自同一个类的实例时,即称它们共享相同的代码。多个线程操作相同的数据,与它们的代码无关。当共享访问相同的对象时,即它们共享相同的数据。当线程被构造时,需要的代码和数据通过一个对象作为构造函数 实参传递进去,这个对象就是一个实现了Runnable接口 的类的实例。
通过铁路售票程序来理解实现多线程:
??? ?? 一个线程对象只能启动一个线程,无论你调用多少遍start()方法,结果只有一个线程。
?
?
?
JAVA多线程基础:http://tomyz0223.iteye.com/blog/1001778
?
?
关于守护线程:
? ? ? 对于Thread来说只想说两个方法,一个是setDaemon(false|true),另一个是join()。首先说说守护线程,这么东西是干什么用的?对于Java应用我们都知道main方法是入口,它的运行代表着主线程开始工作了,我们也知道JVM里面有垃圾回收器的存在使得我们放心让main飞奔,然而这背后的故事是垃圾回收线程作为守护着主线程的守护线程默默的付出着。。。很像那个啥啊,呵呵。令人发指的是main这个畜生背后其实有好几个守护线程默默的付出!当然如果硬是要把守护线程比做女人,非守护线程比做男人的话,那么一个男人背后可以有多个默默付出的女人。Java在设计时就默认了这个现实社会不太能实现的现实,并且强制规定如果男人不在了,这个虚拟世界就over了,看来资本主义社会下长大的孩子创造的东西骨子里是封建社会的血脉啊!扯远了,对的,JVM内部的实现是如果运行的程序只剩下守护线程的话,程序将终止运行,直接结束。所以守护线程是作为辅助线程存在的,主要的作用是提供计数等等辅助的功能。下面写个小例子说明一下:?
public class Test {
public static void main(String[] args) throws Exception{
MyThread mt = new MyThread();
mt.start();
mt.join();
Thread.sleep(3000);
mt.start();
}
}
当线程对象mt运行完成后,我们让主线程休息一下,然后我们再次在这个线程对象上启动线程。结果我们看到:
Exception in thread "main" java.lang.IllegalThreadStateException
也就是这种线程对象一时运行一次完成后,它就再也不能运行第二次了。我们可以看一下它有具体实现:
public synchronized void start() {
if (started)
throw new IllegalThreadStateException();
started = true;
group.add(this);
start0();
}
一个Thread的实例一旦调用start()方法,这个实例的started标记就标记为true,事实中不管这个线程后来有没有执行到底,只要调用了一次start()就再也没有机会运行了,这意味着:
[通过Thread实例的start(),一个Thread的实例只能产生一个线程]
那么如果要在一个实例上产生多个线程(也就是我们常说的线程池),我们应该如何做呢?这就是Runnable接口给我们带来的伟大的功能。
class R implements Runnable{
private int x = 0;
public void run(){
for(int i=0;i<100;i++){
try{
Thread.sleep(10);
}catch(Exception e){}
System.out.println(x++);
}
}
}
正如它的名字一样,Runnable的实例是可运行的,但它自己并不能直接运行,它需要被Thread对象来包装才行运行:
public class Test {
public static void main(String[] args) throws Exception{
new Thread(new R()).start();
}
}
当然这个结果和mt.start()没有什么区别。但如果我们把一个Runnable实例给Thread对象多次包装,我们就可以看到它们实际是在同一实例上启动线程:
public class Test {
public static void main(String[] args) throws Exception{
R r = new R();
for(int i=0;i<10;i++)
new Thread(r).start();
}
}
x是实例对象,但结果是x被加到了999,说明这10个线程是在同一个r对象上运行的。请大家注意,因为这个例子是在单CPU上运行的,所以没有对多个线程同时操作共同的对象进行同步。这里是为了说明的方便而简化了同步,而真正的环境中你无法预知程序会在什么环境下运行,所以一定要考虑同步。
到这里我们做一个完整的例子来说明线程产生的方式不同而生成的线程的区别:
package debug;
import java.io.*;
import java.lang.Thread;
class MyThread extends Thread{
public int x = 0;
public void run(){
System.out.println(++x);
}
}
class R implements Runnable{
private int x = 0;
public void run(){
System.out.println(++x);
}
}
public class Test {
public static void main(String[] args) throws Exception{
for(int i=0;i<10;i++){
Thread t = new MyThread();
t.start();
}
Thread.sleep(10000);//让上面的线程运行完成
R r = new R();
for(int i=0;i<10;i++){
Thread t = new Thread(r);
t.start();
}
}
}
上面10个线程对象产生的10个线程运行时打印了10次1。下面10个线程对象产生的10个线程运行时打印了1到10。我们把下面的10个线程称为同一实例(Runnable实例)的多个线程。来源:http://dev.yesky.com/186/2547686.shtml
?
?
?
?
?