您的位置:首页 > 编程语言 > Java开发

Java 多线程——基础知识

2014-03-25 14:59 323 查看
java 多线程 目录:

Java 多线程——基础知识

Java 多线程 —— synchronized关键字

java 多线程——一个定时调度的例子

java 多线程——quartz 定时调度的例子

java 多线程—— 线程等待与唤醒

在这篇文章里,我们关注多线程。多线程是一个复杂的话题,包含了很多内容,这篇文章主要关注线程的基本属性、如何创建线程、线程的状态切换以及线程通信等。

线程是操作系统运行的基本单位,它被封装在进程中,一个进程可以包含多个线程。即使我们不手动创造线程,进程也会有一个默认的线程在运行。

对于JVM来说,当我们编写一个单线程的程序去运行时,JVM中也是有至少两个线程在运行,一个是我们创建的程序,一个是垃圾回收。

一、 线程基本信息

 我们可以通过Thread.currentThread()方法获取当前线程的一些信息,并对其进行修改。

 我们来看以下代码:

public class test_7 {
public static void main(String [] args){
MutThread m = new MutThread();
Thread t1=new Thread(m,"windows 1");
Thread t2=new Thread(m,"windows 2");
Thread t3=new Thread(m,"windows 3");
t1.start();
t2.start();
t3.start();
}

}

class MutThread implements Runnable
{
private int ticket = 100;
public void run() {
while(ticket>0){
System.out.println("ticket "+ticket--+" is saled by "+Thread.currentThread().getName());
}
}

}


View Code
结果正如前面分析的那样,程序在内存中仅创建了一个资源,而新建的三个线程都是基于访问这同一资源的,并且由于每个线程上所运行的是相同的代码,因此它们执行的功能也是相同的。

可见,如果现实问题中要求必须创建多个线程来执行同一任务,而且这多个线程之间还将共享同一个资源,那么就可以使用实现Runnable接口的方式来创建多线程程序。而这一功能通过扩展Thread类是无法实现的,想想看,为什么?

实现Runnable接口相对于扩展Thread类来说,具有无可比拟的优势。这种方式不仅有利于程序的健壮性,使代码能够被多个线程共享,而且代码和数据资源相对独立,从而特别适合多个具有相同代码的线程去处理同一资源的情况。这样一来,线程、代码和数据资源三者有效分离,很好地体现了面向对象程序设计的思想。因此,几乎所有的多线程程序都是通过实现Runnable接口的方式来完成的。

三 、线程的状态切换

  对于线程来讲,从我们创建它一直到线程运行结束,在这个过程中,线程的状态可能是这样的:

创建:已经有Thread实例了, 但是CPU还有为其分配资源和时间片。

就绪:线程已经获得了运行所需的所有资源,只等CPU进行时间调度。

运行:线程位于当前CPU时间片中,正在执行相关逻辑。

休眠:一般是调用Thread.sleep后的状态,这时线程依然持有运行所需的各种资源,但是不会被CPU调度。

挂起:一般是调用Thread.suspend后的状态,和休眠类似,CPU不会调度该线程,不同的是,这种状态下,线程会释放所有资源。

死亡:线程运行结束或者调用了Thread.stop方法。

  下面我们来演示如何进行线程状态切换,首先我们会用到下面方法:

Thread()或者Thread(Runnable):构造线程。

Thread.start:启动线程。

Thread.sleep:将线程切换至休眠状态。

Thread.interrupt:中断线程的执行。

Thread.join:等待某线程结束。

Thread.yield:剥夺线程在CPU上的执行时间片,等待下一次调度。

Object.wait:将Object上所有线程锁定,直到notify方法才继续运行。

Object.notify:随机唤醒Object上的1个线程。

Object.notifyAll:唤醒Object上的所有线程。

线程等待与唤醒

  这里主要使用Object.wait和Object.notify方法。需要注意的是,wait和notify都必须针对同一个对象,当我们使用实现Runnable接口的方式来创建线程时,应该是在Runnable对象而非Thread对象上使用这两个方法。

线程的休眠与唤醒

public class test_8 {

public static void main(String[] args) throws InterruptedException
{
sleepTest();
}

private static void sleepTest() throws InterruptedException
{
Thread thread = new Thread()
{
public void run()
{
System.out.println("线程 " + Thread.currentThread().getName() + "将要休眠5分钟。");
try
{
Thread.sleep(5*60*1000);
}
catch(InterruptedException ex)
{
System.out.println("线程 " + Thread.currentThread().getName() + "休眠被中断。");
}
System.out.println("线程 " + Thread.currentThread().getName() + "休眠结束。");
}
};
thread.setDaemon(true);
thread.start();
Thread.sleep(500);
thread.interrupt();
}
}


线程在休眠过程中,我们可以使用Thread.interrupt将其唤醒,这时线程会抛出InterruptedException。

结果:

线程 Thread-0将要休眠5分钟。
线程 Thread-0休眠被中断。
线程 Thread-0休眠结束。

线程的终止

虽然有Thread.stop方法,但该方法是不被推荐使用的,我们可以利用上面休眠与唤醒的机制,让线程在处理IterruptedException时,结束线程。

public class test_9 {
public static void main(String[] args)
{
stopTest();
}

private static void stopTest()
{
Thread thread = new Thread()
{
public void run()
{
System.out.println("线程运行。");
try {
Thread.sleep(1*60*1000);
} catch (InterruptedException e) {
System.out.println("线程中断,结束线程");
return ;
}
System.out.println("线程正常结束");

}
};
thread.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}

}


结果:

线程运行。
线程中断,结束线程

线程的同步等待

当我们在主线程中创建了10个子线程,然后我们期望10个子线程全部结束后,主线程在执行接下来的逻辑,这时,就该Thread.join了。

public class test_10 {
public static void main(String[] args) throws InterruptedException
{
joinTest();
}

private static void joinTest() throws InterruptedException
{
Thread thread = new Thread()
{
public void run()
{
try
{
for(int i = 0; i < 10; i++)
{
System.out.println("线程在运行---"+i);
Thread.sleep(1000);
}
}
catch(InterruptedException ex)
{
ex.printStackTrace();
}

}
};
thread.setDaemon(true);
thread.start();
thread.join();
System.out.println("主线程正常结束。");
}

}


结果:

线程在运行---0
线程在运行---1
线程在运行---2
线程在运行---3
线程在运行---4
线程在运行---5
线程在运行---6
线程在运行---7
线程在运行---8
线程在运行---9
主线程正常结束。

注释掉

//thread.join();

结果:

主线程正常结束。
线程在运行---0

参考

Java创建线程的两个方法

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: