黑马程序员-java学习之线程
2013-05-07 23:26
253 查看
-------android培训、java培训、期待与您交流!
----------
进程和线程:
进程是程序的一次动态执行过程,它对应了从代码加载、执行至执行完毕的一个完整过程,线程是比进程更小的单
位,一个进程执行过程中可以产生多个线程,每个线程有自身的产生、存在和消亡的过程,也是一个动态的概念。每
个进程都有一段专用的内存区域,而线程间可以共享相同的内存区域(包括代码和数据),并利用这些共享单元来实现
数据交换、实时通信与必要的同步操作。
每个Java程序都有一个默认的主线程。Java程序是从主类的main方法开始执行。当JVM加载代码,发现main方法后
就启动一个线程,这个线程就称作"主线程",该线程负责执行main方法。在main方法中再创建的线程就是其他线程。
如果main方法中没有创建其他线程,那么当main方法返回时JVM就会结束Java应用程序。但如果main方法中创建了
其他线程,那么JVM就要在主线程和其他线程之间轮流切换,保证每个线程都有机会使用CPU资源,main方法返回
(主线程结束)JVM也不会结束,要一直等到该程序所有线程全部结束才结束Java程序(另外一种情况是:程序中调用了
Runtime类的exit方法,并且安全管理器允许退出操作发生。这时JVM也会结束该程序)。
在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口。
对于直接继承Thread的类来说,代码大致框架是:
先看一个简单的例子:
【运行结果】:
A运行0
A运行1
A运行2
A运行3
A运行4
B运行0
B运行1
B运行2
B运行3
B运行4
我们会发现这些都是顺序执行的,说明我们的调用方法不对,应该调用的是start()方法。
当我们把上面的主函数修改为如下所示的时候:
然后运行程序,输出的可能的结果如下:
A运行0
B运行0
B运行1
B运行2
B运行3
B运行4
A运行1
A运行2
A运行3
A运行4
因为需要用到CPU的资源,所以每次的运行结果基本是都不一样的,呵呵。
注意:虽然我们在这里调用的是start()方法,但是实际上调用的还是run()方法的主体
Java中实现多线程有两种方法:
1、继承Thread类,覆盖run()方法:使用Thread子类创建线程的优点是可以在子类中增加新的成员变量或方法,使线
程具有某种属性或功能。但Java不支持多继承,Thread类的子类不能再扩展其他的类。
2、实现Runnable接口:用Thread类直接创建线程对象,使用构造函数Thread(Runnabletarget)(参数target是一个
Runnable接口),创建线程对象时必须向构造方法参数传递一个实现Runnable接口类的实例,该实例对象称作所创线
程的目标对象。当线程调用start()方法,一旦轮到它使用CPU资源,目标对象自动调用接口中的run()方法(接口回
调)。线程间可以共享相同的内存单元(包括代码和数据),并利用这些共享单元来实现数据交换、实时通信与必要的同
步操作。对于Thread(Runnabletarget)创建的使用同一目标对象的线程,可以共享该目标对象的成员变量和方法。
另外,创建目标对象类在必要时还可以是某个特定类的子类,因此,使用Runnable接口比使用Thread的子类更具有
灵活性。(注意:具有相同目标对象的线程,run()方法中的局部变量相互独立,互不干扰)
在线程中启动其他线程,当线程调用start()方法启动,使之从新建态进入就绪队列,一旦得到CPU资源就脱离创建它
的主线程,开始自己的生命周期。
线程的常用方法:
start():线程调用该方法将启动线程,从新建态进入就绪队列,一旦享用CPU资源就可以脱离创建它的线程,独立开始
自己的生命周期。
run():Thread类的run()方法与Runnable接口中的run()方法功能和作用相同,都用来定义线程对象被调度后所进行的操
作,都是系统自动调用而用户不得引用的方法。run()方法执行完毕,线程就成死亡状态,即线程释放了分配给它的内
存(死亡态线程不能再调用start()方法)。在线程没有结束run()方法前,不能让线程再调用start()方法,否则将发生
IllegalThreadStateException异常。
sleep(intmillsecond):有时,优先级高的线程需要优先级低的线程做一些工作来配合它,此时为让优先级高的线程让
出CPU资源,使得优先级低的线程有机会运行,可以使用sleep(intmillsecond)方法。线程在休眠时被打断,JVM就抛
出InterruptedException异常。因此,必须在try-catch语句块中调用sleep方法。
isAlive():当线程调用start()方法并占有CPU资源后该线程的run()方法开始运行,在run()方法没有结束之前调用isAlive
()返回true,当线程处于新建态或死亡态时调用isAlive()返回false。
注意:一个已经运行的线程在没有进入死亡态时,不要再给它分配实体,由于线程只能引用最后分配的实体,先前的
实体就成为了"垃圾",并且不能被垃圾回收机制收集。
currentThread():是Thread类的类方法,可以用类名调用,返回当前正在使用CPU资源的线程。
interrupt():当线程调用sleep()方法处于休眠状态,一个占有CPU资源的线程可以让休眠的线程调用interrupt()方法"吵
醒"自己,即导致线程发生IllegalThreadStateException异常,从而结束休眠,重新排队等待CPU资源。
GUI线程:JVM在运行包含图形界面应用程序时,会自动启动更多线程,其中有两个重要的线程:AWT-EventQueue
和AWT-Windows。AWT-EventQueue线程负责处理GUI事件,AWT-Windows线程负责将窗体或组件绘制到桌面。
线程同步:(用synchronized修饰某个方法,该方法修改需要同步的变量;或用volatile修饰基本变量)
当两个或多个线程同时访问一个变量,并且一个线程需要修改这个变量时,应对这样的问题进行处理,否则可能发生
混乱。
要处理线程同步,可以把修改数据的方法用关键字synchronized修饰。一个方法使用synchronized修饰,当一个线程
A使用这个方法时,其他线程想使用该方法时就必须等待,直到线程A使用完该方法。所谓同步就是多个线程都需要
使用一个synchronized修饰的方法。
----------
进程和线程:
进程是程序的一次动态执行过程,它对应了从代码加载、执行至执行完毕的一个完整过程,线程是比进程更小的单
位,一个进程执行过程中可以产生多个线程,每个线程有自身的产生、存在和消亡的过程,也是一个动态的概念。每
个进程都有一段专用的内存区域,而线程间可以共享相同的内存区域(包括代码和数据),并利用这些共享单元来实现
数据交换、实时通信与必要的同步操作。
每个Java程序都有一个默认的主线程。Java程序是从主类的main方法开始执行。当JVM加载代码,发现main方法后
就启动一个线程,这个线程就称作"主线程",该线程负责执行main方法。在main方法中再创建的线程就是其他线程。
如果main方法中没有创建其他线程,那么当main方法返回时JVM就会结束Java应用程序。但如果main方法中创建了
其他线程,那么JVM就要在主线程和其他线程之间轮流切换,保证每个线程都有机会使用CPU资源,main方法返回
(主线程结束)JVM也不会结束,要一直等到该程序所有线程全部结束才结束Java程序(另外一种情况是:程序中调用了
Runtime类的exit方法,并且安全管理器允许退出操作发生。这时JVM也会结束该程序)。
在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口。
对于直接继承Thread的类来说,代码大致框架是:
class类名extendsThread{方法1;方法2;…publicvoidrun(){//othercode…}
属性1;属性2;…}
先看一个简单的例子:
/***@authorRollen-Holt继承Thread类,直接调用run方法**/
classhelloextendsThread{
privateStringname;
publichello(){
}
publichello(Stringname){
this.name=name;
}
publicvoidrun(){
for(inti=0;i<5;i++){
System.out.println(name+"运行"+i);
}
}
publicstaticvoidmain(String[]args){
helloh1=newhello("A");
helloh2=newhello("B");
h1.run();
h2.run();
}
}
【运行结果】:
A运行0
A运行1
A运行2
A运行3
A运行4
B运行0
B运行1
B运行2
B运行3
B运行4
我们会发现这些都是顺序执行的,说明我们的调用方法不对,应该调用的是start()方法。
当我们把上面的主函数修改为如下所示的时候:
publicstaticvoidmain(String[]args){
helloh1=newhello("A");
helloh2=newhello("B");
h1.start();
h2.start();
}
然后运行程序,输出的可能的结果如下:
A运行0
B运行0
B运行1
B运行2
B运行3
B运行4
A运行1
A运行2
A运行3
A运行4
因为需要用到CPU的资源,所以每次的运行结果基本是都不一样的,呵呵。
注意:虽然我们在这里调用的是start()方法,但是实际上调用的还是run()方法的主体
Java中实现多线程有两种方法:
1、继承Thread类,覆盖run()方法:使用Thread子类创建线程的优点是可以在子类中增加新的成员变量或方法,使线
程具有某种属性或功能。但Java不支持多继承,Thread类的子类不能再扩展其他的类。
2、实现Runnable接口:用Thread类直接创建线程对象,使用构造函数Thread(Runnabletarget)(参数target是一个
Runnable接口),创建线程对象时必须向构造方法参数传递一个实现Runnable接口类的实例,该实例对象称作所创线
程的目标对象。当线程调用start()方法,一旦轮到它使用CPU资源,目标对象自动调用接口中的run()方法(接口回
调)。线程间可以共享相同的内存单元(包括代码和数据),并利用这些共享单元来实现数据交换、实时通信与必要的同
步操作。对于Thread(Runnabletarget)创建的使用同一目标对象的线程,可以共享该目标对象的成员变量和方法。
另外,创建目标对象类在必要时还可以是某个特定类的子类,因此,使用Runnable接口比使用Thread的子类更具有
灵活性。(注意:具有相同目标对象的线程,run()方法中的局部变量相互独立,互不干扰)
在线程中启动其他线程,当线程调用start()方法启动,使之从新建态进入就绪队列,一旦得到CPU资源就脱离创建它
的主线程,开始自己的生命周期。
线程的常用方法:
start():线程调用该方法将启动线程,从新建态进入就绪队列,一旦享用CPU资源就可以脱离创建它的线程,独立开始
自己的生命周期。
run():Thread类的run()方法与Runnable接口中的run()方法功能和作用相同,都用来定义线程对象被调度后所进行的操
作,都是系统自动调用而用户不得引用的方法。run()方法执行完毕,线程就成死亡状态,即线程释放了分配给它的内
存(死亡态线程不能再调用start()方法)。在线程没有结束run()方法前,不能让线程再调用start()方法,否则将发生
IllegalThreadStateException异常。
sleep(intmillsecond):有时,优先级高的线程需要优先级低的线程做一些工作来配合它,此时为让优先级高的线程让
出CPU资源,使得优先级低的线程有机会运行,可以使用sleep(intmillsecond)方法。线程在休眠时被打断,JVM就抛
出InterruptedException异常。因此,必须在try-catch语句块中调用sleep方法。
isAlive():当线程调用start()方法并占有CPU资源后该线程的run()方法开始运行,在run()方法没有结束之前调用isAlive
()返回true,当线程处于新建态或死亡态时调用isAlive()返回false。
注意:一个已经运行的线程在没有进入死亡态时,不要再给它分配实体,由于线程只能引用最后分配的实体,先前的
实体就成为了"垃圾",并且不能被垃圾回收机制收集。
currentThread():是Thread类的类方法,可以用类名调用,返回当前正在使用CPU资源的线程。
interrupt():当线程调用sleep()方法处于休眠状态,一个占有CPU资源的线程可以让休眠的线程调用interrupt()方法"吵
醒"自己,即导致线程发生IllegalThreadStateException异常,从而结束休眠,重新排队等待CPU资源。
GUI线程:JVM在运行包含图形界面应用程序时,会自动启动更多线程,其中有两个重要的线程:AWT-EventQueue
和AWT-Windows。AWT-EventQueue线程负责处理GUI事件,AWT-Windows线程负责将窗体或组件绘制到桌面。
线程同步:(用synchronized修饰某个方法,该方法修改需要同步的变量;或用volatile修饰基本变量)
当两个或多个线程同时访问一个变量,并且一个线程需要修改这个变量时,应对这样的问题进行处理,否则可能发生
混乱。
要处理线程同步,可以把修改数据的方法用关键字synchronized修饰。一个方法使用synchronized修饰,当一个线程
A使用这个方法时,其他线程想使用该方法时就必须等待,直到线程A使用完该方法。所谓同步就是多个线程都需要
使用一个synchronized修饰的方法。
相关文章推荐
- 黑马程序员——学习日记12 java线程同步
- 黑马程序员-Java学习06-线程1
- 黑马程序员 java学习笔记 Day2:线程
- 黑马程序员—11—java基础:有关线程通信的学习笔记和学习心得体会
- 黑马程序员————java线程的学习
- 黑马程序员--Java学习笔记之多线程(自定义线程的两种方式对比、线程状态、线程安全)
- 黑马程序员---java线程Timer学习与总结
- 黑马程序员-----java线程学习与总结
- 黑马程序员 Java基础学习笔记 线程间同信
- 黑马程序员 【】java学习之路——线程
- 黑马程序员_Java学习日记第四天-线程、Java1.5的新特性
- 黑马程序员——java学习日记十
- Java基础学习笔记(十)线程的创建总结
- 黑马程序员--Java基础学习(网络编程)第二十四天
- 黑马程序员--Java高级--网络编程学习1
- 黑马程序员--学习笔记--Java中的重载和重写
- 黑马程序员--Java基础学习笔记【参数传递、访问控制符、内部类】
- Java学习笔记之进程和线程
- 黑马程序员-JAVA学习之网络编程UDP篇
- 黑马程序员——java基础:异常学习日志