目标:
了解设置和取得线程的名称。
了解线程的强制运行。
了解线程的休眠。
了解线程的礼让。
了解线程的中断操作。
具体内容:在多线程中所有的操作方法实际上都是从Thread类开始的。所有的操作都是在Thread类之中的。
线程操作的主要方法
- NO 方法名称 类型 描述
- 1 public Thread(Runnable target) 构造 接收Runnable接口子类对象,实例化Thread对象
- 2 public Thread(Runnable target,String name) 构造 接收Runnable接口子类对象,实例化Thread对象,并设置线程名称
- 3 public Thread(String name) 构造 实例化Thread对象,并设置线程名称。
- 4 public static Thread currentThread() 普通 返回目前正在执行的线程。
- 5 public final String getName() 普通 返回线程的名称
- 6 public final int getPriority() 普通 返回线程的优先级
- 7 public boolean isInterrupted() 普通 判断目前线程是否被中断,如果是,返回true,否则返回false
- 8 public final boolean isActive() 普通 判断线程是否在活动,如果是返回true,否则返回false
- 9 public final void join() throws InterruptedException 普通 等待线程死亡
- 10 public final synchronized void join(long millis) throws
- InterruptedException 普通 等待millis毫秒后,线程死亡。
- 11 public void run() 普通 执行线程
- 12 public final void setName() 普通 设定线程名称
- 13 public final void setPriority(int newPriority) 普通 设定线程的优先级
- 14 public static void sleep(long millis) throws
- InterruptedException 普通 使目前正在执行的线程休眠millis毫秒
- 15 public void start() 普通 开始执行线程。
- 16 public static void yield() 普通 将目前正在执行的线程暂停一次,允许其他线程执行
- 17 public final void setDaemon(boolean on) 普通 将一个线程设置成后台运行
- 18 public final void setPriority(int newPriority) 普通 更改线程的优先级
线程名称
取得和设置线程名称
在Thread类中,可以通过getName()方法取得线程名称,通过setName()方法设置线程的名称。
线程的名称一般在启动线程前设置,但也允许为已经存在的线程设置名称。允许两个Thread对象有相同的名字,但为了清晰,应该尽量避免这种情况的发生。
另外,如果程序并没有为线程指定名称,则系统会自动的为线程分配一个名称。
线程的名称最好在线程启动前设置,避免重名。
- class MyThread implements Runnable{
- public void run(){
- for(int i=0;i<3;i++){
- System.out.println(Thread.currentThread().getName()
- + "运行,i = " + i) ;
- }
- }
- };
- public class ThreadNameDemo{
- public static void main(String args[]){
- MyThread mt = new MyThread() ;
- new Thread(mt).start() ;
- new Thread(mt,"线程-A").start() ;
- new Thread(mt,"线程-B").start() ;
- new Thread(mt).start() ;
- new Thread(mt).start() ;
- }
- };
从执行效果来看,指定的名称会自动出现,如果没有指定会发现线程使用自动编号的方式完成,按照:Thread-0、Thread-1 依次编号,实际上肯定在类中存在一个static属性,用于记录编号。
取得当前线程
程序可以通过currentThread()方法取得当前正在运行的线程对象。
- class MyThread implements Runnable{
- public void run(){
- for(int i=0;i<3;i++){
- System.out.println(Thread.currentThread().getName()
- + "运行,i = " + i) ;
- }
- }
- };
- public class CurrentThreadDemo{
- public static void main(String args[]){
- MyThread mt = new MyThread() ;
- new Thread(mt,"线程").start() ;
- mt.run() ;
- }
- };
此时发现,程序中由主方法直接通过线程对象调用里面的run()方法,所以输出的结果中包含了一个“main”,此线程就是“mt.run”, 因为调用此语句是由主方法完成的,也就是说实际上主方法本身也是一个线程——主线程。
问题:既然主方法都是以线程的形式出现的,那么Java运行时到底启动了多少个线程?
回答:至少启动了两个。从目前的知识上看,每当Java程序执行的时候,实际上都会启动一个JVM,每一个JVM实际上就是在操作系统中启动了一个进程。Java中本身具备了垃圾收集机制,所以Java运行时至少启动两个线程:主线程、GC。
判断线程是否启动
- class MyThread implements Runnable{
- public void run(){
- for(int i=0;i<3;i++){
- System.out.println(Thread.currentThread().getName()
- + "运行,i = " + i) ;
- }
- }
- };
- public class ThreadAliveDemo{
- public static void main(String args[]){
- MyThread mt = new MyThread() ;
- Thread t = new Thread(mt,"线程");
- System.out.println("线程开始执行之前 --> " + t.isAlive()) ;
- t.start() ;
- System.out.println("线程开始执行之后 --> " + t.isAlive()) ;
- for(int i=0;i<3;i++){
- System.out.println(" main运行 --> " + i) ;
- }
-
- System.out.println("代码执行之后 --> " + t.isAlive()) ;
-
- }
- };
发现调用start方法之后线程就激活了,如果线程执行任务完毕后就会被关闭。如果没有执行完毕,仍处于激活状态。
线程的强制运行
在线程操作中,可以使用join()方法让一个线程强制运行,线程强制运行期间,其他线程无法运行,必须等待此线程完成之后才可以继续运行。
- class MyThread implements Runnable{
- public void run(){
- for(int i=0;i<50;i++){
- System.out.println(Thread.currentThread().getName()
- + "运行,i = " + i) ;
- }
- }
- };
- public class ThreadJoinDemo{
- public static void main(String args[]){
- MyThread mt = new MyThread() ;
- Thread t = new Thread(mt,"线程");
- t.start() ;
- for(int i=0;i<50;i++){
- if(i>10){
- try{
- t.join() ;
- }catch(InterruptedException e){}
- }
- System.out.println("Main线程运行 --> " + i) ;
- }
- }
- };
线程的休眠
在程序中允许一个线程进行暂时的休眠,直接使用Thread.sleep()方法即可。
- class MyThread implements Runnable{
- public void run(){
- for(int i=0;i<50;i++){
- try{
- Thread.sleep(500) ;
- }catch(InterruptedException e){}
- System.out.println(Thread.currentThread().getName()
- + "运行,i = " + i) ;
- }
- }
- };
- public class ThreadSleepDemo{
- public static void main(String args[]){
- MyThread mt = new MyThread() ;
- Thread t = new Thread(mt,"线程");
- t.start() ;
- }
- };
会发现每隔500毫秒,执行一次。
线程的中断
当一个线程运行的时候,另外一个线程可以直接通过interrupt()方法 中断其运行状态。
- class MyThread implements Runnable{
- public void run(){
- System.out.println("1、进入run()方法") ;
- try{
- Thread.sleep(10000) ;
- System.out.println("2、已经完成了休眠") ;
- }catch(InterruptedException e){
- System.out.println("3、休眠被终止") ;
- return ;
- }
- System.out.println("4、run()方法正常结束") ;
- }
- };
- public class ThreadInterruptDemo{
- public static void main(String args[]){
- MyThread mt = new MyThread() ;
- Thread t = new Thread(mt,"线程");
- t.start() ;
- try{
- Thread.sleep(2000) ;
- }catch(InterruptedException e){
- System.out.println("3、休眠被终止") ;
- }
- t.interrupt() ;
- }
- };
后台进程
在Java中,只要有一个程序没有执行完(一个线程在运行),则整个Java的进程就不会消失,所以此时可以设置一个后台线程,这样即使Java进程结束了,此后台线程依然会继续运行,也就是说不影响进程的结束。要想实现这样的操作,直接使用setDaemon()方法即可。
- class MyThread implements Runnable{
- public void run(){
- while(true){
- System.out.println(Thread.currentThread().getName() + "在运行。") ;
- }
- }
- };
- public class ThreadDaemonDemo{
- public static void main(String args[]){
- MyThread mt = new MyThread() ;
- Thread t = new Thread(mt,"线程");
- t.setDaemon(true) ;
- t.start() ;
- }
- };
会发现没有打印任何东西,如果设置为false的话则会一直打印,不会结束进程。
线程的优先级
在Java的线程操作中,所有的线程在运行前都会保持在就绪状态,那么此时哪个线程的优先级高,哪个线程就有可能被先执行。
- class MyThread implements Runnable{
- public void run(){
- for(int i=0;i<5;i++){
- try{
- Thread.sleep(500) ;
- }catch(InterruptedException e){}
- System.out.println(Thread.currentThread().getName()
- + "运行,i = " + i) ;
- }
- }
- };
- public class ThreadPriorityDemo{
- public static void main(String args[]){
- Thread t1 = new Thread(new MyThread(),"线程A") ;
- Thread t2 = new Thread(new MyThread(),"线程B") ;
- Thread t3 = new Thread(new MyThread(),"线程C") ;
- t1.setPriority(Thread.MIN_PRIORITY) ;
- t2.setPriority(Thread.MAX_PRIORITY) ;
- t3.setPriority(Thread.NORM_PRIORITY) ;
- t1.start() ;
- t2.start() ;
- t3.start() ;
- }
- };
主线程的优先级是NORM_PRIORITY 为5 是中等级别。
默认的线程优先级也是NORM_PRIORITY。
程序示例如下:
- public class MainPriorityDemo{
- public static void main(String args[]){
- System.out.println("主方法的优先级:" +
- Thread.currentThread().getPriority()) ;
- System.out.println("MAX_PRIORITY = " + Thread.MAX_PRIORITY) ;
- System.out.println("NORM_PRIORITY = " + Thread.NORM_PRIORITY) ;
- System.out.println("MIN_PRIORITY = " + Thread.MIN_PRIORITY) ;
- }
- };
线程的礼让
在线程操作中,也可以使用yield()方法将一个线程的操作暂时让给其他线程执行。
- class MyThread implements Runnable{
- public void run(){
- for(int i=0;i<5;i++){
- try{
- Thread.sleep(500) ;
- }catch(Exception e){}
- System.out.println(Thread.currentThread().getName()
- + "运行,i = " + i) ;
- if(i==2){
- System.out.print("线程礼让:") ;
- Thread.currentThread().yield() ;
- }
- }
- }
- };
- public class ThreadYieldDemo{
- public static void main(String args[]){
- MyThread my = new MyThread() ;
- Thread t1 = new Thread(my,"线程A") ;
- Thread t2 = new Thread(my,"线程B") ;
- t1.start() ;
- t2.start() ;
- }
- };
总结:
重点是掌握线程的操作方法,对于这些操作方法只需要从Thread类中查找即可。
线程操作范例
实例要求:设计一个线程操作类,要求可以产生三个线程对象,并可以分别设置三个线程的休眠时间,如下所示:
线程A,休眠10秒。
线程B,休眠20秒
线程C,休眠30秒
分析:已知线程的实现有两种方式,一种是继承Thread类,另外一种是实现Runnable接口。而且在类中应该保存线程名称和休眠时间两个属性。
(一)使用Thread类
在Thread类中直接存在了name属性。
- class MyThread extends Thread{
- private int time ;
- public MyThread(String name,int time){
- super(name) ;
- this.time = time ;
- }
- public void run(){
- try{
- Thread.sleep(this.time) ;
- }catch(InterruptedException e){
- e.printStackTrace() ;
- }
- System.out.println(Thread.currentThread().getName() + "线程,休眠"
- + this.time + "毫秒。") ;
- }
- };
- public class ExecDemo01{
- public static void main(String args[]){
- MyThread mt1 = new MyThread("线程A",10000) ;
- MyThread mt2 = new MyThread("线程B",20000) ;
- MyThread mt3 = new MyThread("线程C",30000) ;
- mt1.start() ;
- mt2.start() ;
- mt3.start() ;
- }
- };
(二)使用Runnable
如果使用Runnable接口,则类中是没有线程名称存在的,所以应该单独建立一个name属性,以保存线程的名称。
- class MyThread implements Runnable{
- private String name ;
- private int time ;
- public MyThread(String name,int time){
- this.name = name ;
- this.time = time ;
- }
- public void run(){
- try{
- Thread.sleep(this.time) ;
- }catch(InterruptedException e){
- e.printStackTrace() ;
- }
- System.out.println(this.name + "线程,休眠"
- + this.time + "毫秒。") ;
- }
- };
- public class ExecDemo02{
- public static void main(String args[]){
- MyThread mt1 = new MyThread("线程A",10000) ;
- MyThread mt2 = new MyThread("线程B",20000) ;
- MyThread mt3 = new MyThread("线程C",30000) ;
- new Thread(mt1).start() ;
- new Thread(mt2).start() ;
- new Thread(mt3).start() ;
- }
- };