结合别人的博客来详细的说明一下java中的线程,这篇文章合适那些对java线程的使用有一点了解的人
问题一:线程在哪里执行的?
我们可能都听说过jvm中有堆栈的概念,这里的栈就是指线程栈,也就是线程执行的地方,所有的程序都有一个main线程的线程栈。
请看图例:
当程序刚开始运行时只有一个main线程栈,当调用 下面的代码时启动了一个线程,所以又多了一个线程栈,所有threadMethod()方法中的变量都放在栈B中,栈A和栈B是两个完全独立的内存空间。
new JavaThreadDemo().threadMethod();//启动新线程
问题二 : 线程的生命周期有哪些?
线程的生命周期包括五种状态:新建、可运行状态、运行状态、阻塞、死亡。
请参考下图:
新建:创建了一个新的线程对象,但是还没有调用线程中start()方法,此时线程处于新建状态。代码示例如下
Thread a = new Thread();
a.start();
可运行状态:调用线程的start()方法,线程进入可运行状态,此时线程等待着JVM的调度程序来执行。
运行状态:线程调度程序从众多的可运行状态线程中选择一个线程来运行,好比主帅选择一个大将来上阵较量。这也是线程进入运行状态的唯一方式,必须由JVM来调度。
阻塞状态:线程的等待、睡眠和阻塞统称为阻塞状态,此时线程依然是活得,处于待命状态,知道某个条件出现时,即可返回可运行状态。
阻塞状态时一个很重要的状态,如果来理解多线程编程,一定要理解这个状态.
//下面的代码展示一个多线程web服务器模型
//这个列表中放需要处理的任务
public LinkedList<SocketTask> taskQueue= new LinkedList<SocketTask>();
//这里是工作线程的run方法
public void run(){
synchronized(taskQueue){
if(taskQueue.isEmpty())
taskQueue.wait();
else
//do handle it
}
}
代码片段可能很难理解,可以参考我的完整代码, 一个多线程下载的示例
死亡状态:当线程的run()方法执行完毕后,线程即结束。此时线程已经不在存在,它所占用的所有资源都会被回收。
线程常用方法的使用
Java在多线程处理方法是十分强大的,而且API也十分简单,所以是必须掌握的内容,这里举例说明一些常用的方法
静态方法 sleep(long m) :会导致当前线程暂停执行m毫秒,m毫秒之后继续执行
//程序会打印before sleep之后暂停3秒,然后打印 sleep over
System.out.println("before sleep");
Thread.sleep(3000);
System.out.print("sleep over");
start()和run()方法: 把这两个方法放到一起来讲,如果想要启动一个线程就调用他的start()方法, 那么jvm会为你分配线程所需要的执行栈来启动一个新的线程,线程开始执行后执行的的run()里面的内容,如果我们不调用start方法,而是直接调用run(),那么,这只是此普通的调用,和其他的方法调用没有任何区别。
//这是一个匿名内部类,方法执行后会启动一个新线程
new Thread(){
@Override
public void run() {
System.out.println("I am a new thread ...");
}
}.start();
-----------------------------------------------------
//这样代码执行后还是只有一个线程,只是普通的方法调用
class MyThread extends Thread{
public static void main(String args[]){
Thread t = new MyThread();
t.run();
}
public void run(){
System.out.println("run method");
}
}
//
suspend()方法和resume()方法, suspend有暂停,挂起的意思,resume是恢复的意思,suspend使线程暂停,知道线程的resume方法被调用, JDK的文档中已经不推荐使用了,因为很容易产生死锁(dead lock),这是在复杂的并发应用中容易造成这样的情况,但简单的一些任务我们还是可以使用的,下面的例子说明的是主程序suspend之后,等待另一个线程任务完成,然后退出,程序中有一些复杂的语法,但也是java中常用的一些表现方式,需要自己掌握的。
package com.kevin.thread;
public class ThreadFunctionTest {
public static void main(String[] args) throws Throwable {
ThreadFunctionTest test = new ThreadFunctionTest();
//主线程将自己传递给新线程
ThreadFunctionTest.Thread1 t1 = test.new Thread1(Thread.currentThread());
t1.start();
new Thread(){
@Override
public void run() {
System.out.println("I am a new thread ...");
}
}.start();
Thread.currentThread().suspend();
System.out.println("main thread over ...");
}
class Thread1 extends Thread{
Thread main;
public Thread1(Thread main) {
this.main = main;
}
public void run() {
try {
Thread.currentThread().sleep(4000);
System.out.println("Thread1 sleep over...");
main.resume();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
join()方法 :意思是等待另一个线程执行完,也可以调用join(long mill),表示只等待多少毫秒,这个方法要好好理解,在哪个线程中调用表示哪个线程等待,下面的例子是主线程等待另一个线程执行完毕才继续
package com.kevin.thread;
public class ThreadFunctionTest {
public static void main(String[] args) throws Throwable {
ThreadFunctionTest test = new ThreadFunctionTest();
ThreadFunctionTest.Thread1 t1 = test.new Thread1(Thread.currentThread());
t1.start();
t1.join();
System.out.println("main thread over ...");
}
class Thread1 extends Thread{
public void run() {
try {
Thread.currentThread().sleep(4000);
System.out.println("Thread1 sleep over...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
yield方法:表示让别的 线程先去执行,这个方法用的不是很多,我还没有想到好的例子来说明,后面如果有例子,我再补充