Java 多线程——基础知识
2014-03-25 14:59
323 查看
java 多线程 目录:
Java 多线程——基础知识
Java 多线程 —— synchronized关键字
java 多线程——一个定时调度的例子
java 多线程——quartz 定时调度的例子
java 多线程—— 线程等待与唤醒
在这篇文章里,我们关注多线程。多线程是一个复杂的话题,包含了很多内容,这篇文章主要关注线程的基本属性、如何创建线程、线程的状态切换以及线程通信等。
线程是操作系统运行的基本单位,它被封装在进程中,一个进程可以包含多个线程。即使我们不手动创造线程,进程也会有一个默认的线程在运行。
对于JVM来说,当我们编写一个单线程的程序去运行时,JVM中也是有至少两个线程在运行,一个是我们创建的程序,一个是垃圾回收。
我们来看以下代码:
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上的所有线程。
线程在休眠过程中,我们可以使用Thread.interrupt将其唤醒,这时线程会抛出InterruptedException。
结果:
线程 Thread-0将要休眠5分钟。
线程 Thread-0休眠被中断。
线程 Thread-0休眠结束。
结果:
线程运行。
线程中断,结束线程
结果:
线程在运行---0
线程在运行---1
线程在运行---2
线程在运行---3
线程在运行---4
线程在运行---5
线程在运行---6
线程在运行---7
线程在运行---8
线程在运行---9
主线程正常结束。
注释掉
结果:
主线程正常结束。
线程在运行---0
参考
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创建线程的两个方法
相关文章推荐
- JAVA基础知识之java多线程时数据同步问题
- Java学习笔记-《Java程序员面试宝典》-第四章基础知识-4.10多线程(4.10.1-4.10.4)
- java从基础知识(十)java多线程(下)
- Java基础知识强化之网络编程笔记05:UDP之多线程实现聊天室案例
- Java多线程核心技术(一):基础知识总结
- java并发多线程基础知识
- Java多线程:多线程基础知识
- Java基础知识强化之多线程笔记05:Java中继承thread类 与 实现Runnable接口的区别
- java基础知识 多线程
- Java基础知识之多线程(2)
- Java多线程基础知识
- JAVA基础知识之多线程——三种实现多线程的方法及区别
- Java基础知识笔记(五:多线程的同步问题)
- java并发多线程基础知识
- Java基础知识强化之多线程笔记04:并行和并发 区别
- JAVA多线程程序开发基础知识
- JAVA基础知识之多线程——线程组和未处理异常
- java基础知识总结-多线程(二)
- JAVA常用基础知识点[继承,抽象,接口,静态,枚举,反射,泛型,多线程...]
- JAVA基础知识之多线程——线程的生命周期(状态)