从线程状态 的图中可以发现,在Java实现多线程的程序中,虽然Thread类实现了Runnable接口,但是操作线程的主要方法并不在Runnable接口中,而是在Thread类中。
Thread类中主要方法
方法名称 | 类型 | 概述 |
---|---|---|
public Thread(Runnable target) | 构造 | 接收Runnable接口子类对象,实例化Thread对象 |
public Thread(Runnable target,String name) | 构造 | 接收Runnable接口子类对象,实例化Thread对象,并设置线程名称 |
public void run() | 普通 | 执行线程 |
。。。。 | 。。 | 。。。。 |
public final void setDemo(boolean on) | 普通 | 将一个线程设置成后台运行 |
下面介绍几种常用的线程操作方法。
- 取得和设置线程的名称
在Thread类中可以通过getName()方法取得线程的名称,还可以通过setName()方法设置线程的名称。
线程的名称一般在启动线程前就设置,但是也可以为在运行的线程设置名称。允许两个线程拥有相同的名称,但应该尽量避免这种情况的发生。
如果没有设置线程的名称,系统会为其自动分配名称。
【取得和设置线程的名称】
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 my=new MyThread();//定义Runnable子类对象
new Thread(my).start();//系统自动设置线程的名称
new Thread(my,"线程-A").start();//手动设置线程的名称
new Thread(my,"线程-B").start();
new Thread(my).start();
}
}
运行结果:
线程-A运行,i=0
Thread-1运行,i=0
线程-B运行,i=0
线程-B运行,i=1
线程-B运行,i=2
Thread-0运行,i=0
Thread-1运行,i=1
线程-A运行,i=1
Thread-1运行,i=2
Thread-0运行,i=1
Thread-0运行,i=2
线程-A运行,i=2
从程序的运行结果中可以发现,没有设置线程名称的线程对象也有了名字而且都是有规律的,分别是Thread-1、Thread-0,从之前讲解的static关键字可以知道,在Thread类中避让存在一个static类型的属性,用于为线程的命名。
了解了以上代码后,下面观察以下的代码
【观察代码的输出】
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 my=new MyThread();//定义Runnable子类对象
new Thread(my,"线程").start();//启动线程
my.run();//直接使用run方法
}
}
运行结果:
main运行, i=0
线程运行, i=0
main运行, i=1
main运行, i=2
线程运行, i=1
线程运行, i=2
在以上程序中,主方法直接通过Runnable接口的子类对象调用其中的run()方法,另外一个是通过线程对象调用start()方法启动的,从结果中可以发现,主方法实际上也是一个线程。
另外要提醒的是,在java中所有的现车都是同时启动的,哪个线程先抢到了CPU的资源,哪个线程就先运行。
说明:Java程序中每次裕兴程序至少启动两个线程。 从之前的学习中可以知道,每当使用Java命令执行一个类时,实际上都会启动一个JVM,每个JVM实际上就是在操作系统中启动了一个进程,,Java本身具有垃圾回收机制。所以在Java运行时至少会启动两个线程,一个main线程,另一个就是垃圾收集线程。
2. 判断线程是否启动
通过前面的讲解可知,通过Thread类中的start()方法通知CPU这个线程已经准备好启动了,然后等待CUP资源,运行此线程,在Java中可以使用isAlive()方法来测试是否已经启动而且任然在运行。
【判断线程是否启动】
class MyThread implements Runnable{
public void run(){//覆写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 my = new MyThread();//实例化Runnable子类对象
Thread t=new Thread(my,"线程");//实例化Thread对象
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());//后面的输出结果不确定
}
}
运行结果:
线程开始执行之前--》false
线程开始执行之后——》true
main 运行--》0
main 运行--》1
main 运行--》2
代码执行之后--》true
线程运行,i=0
线程运行,i=1
线程运行,i=2
以上的代码运行结果是不确定的,有可能到最后线程已经不存活了,但也有可能继续存活,这要看哪个线程先运行。因为线程操作的不确定性,所以当主线程结束时,那么其他线程不会受到影响,并不会随着主线程的结束而结束。
3. 线程的强制运行
在线程操作中,可以使用join()方法让一个线程强制运行,线程强制运行期间,其他线程无法运行,必须等待此线程完成之后才能继续执行。
【线程的强制运行】
class MyThread implements Runnable
{
public void run(){
for (int i=0;i<20 ;i++ )
{
System.out.println(Thread.currentThread().getName()+"运行--》"+i);
}
}
};
public class ThreadJoinDemo
{
public static void main(String args[])
{
MyThread my=new MyThread();
Thread t=new Thread(my,"线程");
t.start();
for (int j=0;j<10 ;j++ )
{
if (j>5)
{
try
{
t.join();//强制t进行强制进行
}
catch (Exception e)
{
}
}
System.out.println("Main 线程运行-->"+j);
}
}
}
运行结果:
Main 线程运行-->0
线程运行--》0
Main 线程运行-->1
Main 线程运行-->2
Main 线程运行-->3
线程运行--》1
Main 线程运行-->4
线程运行--》2
Main 线程运行-->5
线程运行--》3
线程运行--》4
线程运行--》5
线程运行--》6
线程运行--》7
线程运行--》8
线程运行--》9
线程运行--》10
线程运行--》11
线程运行--》12
线程运行--》13
线程运行--》14
线程运行--》15
线程运行--》16
线程运行--》17
线程运行--》18
线程运行--》19
Main 线程运行-->6
Main 线程运行-->7
Main 线程运行-->8
Main 线程运行-->9
从上面的结果可以看出,主线程必须等待这个强制运行的线程完成之后才会继续执行。
4. 线程的休眠
在程序中允许一个线程进行暂时休眠,直接调用Thread.sleep()方法即可实现休眠。
【线程的休眠】
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);
}
}
};
public class ThreadSleepDemo
{
public static void main(String args[])
{
MyThread my=new MyThread();//实例化对象
new Thread(my,"线程").start();//启动线程
}
}
运行结果:
线程运行,i=0
线程运行,i=1
线程运行,i=2
线程运行,i=3
线程运行,i=4
以上程序在执行时,每次输出都会间隔500ms,达到延迟操作的效果。
5. 中断线程
当一个线程运行时,另一个线程可以通过interrupt()方法即可实现休眠。
【线程的中断】
class MyThread implements Runnable
{
public void run(){
System.out.println("1、进入run方法 ");
try
{
Thread.sleep(10000);//休眠10s
System.out.println("2、已经完成休眠");
}
catch (Exception e)
{
System.out.println("3、休眠被终止了");
return;//让程序返回被调用处
}
}
}
public class ThreadInterruptDemo
{
public static void main(String args[])
{
MyThread my=new MyThread();//实例化Runnable接口对象
Thread t=new Thread(my,"线程");//实例化线程对象
t.start();
try
{
Thread.sleep(2000);//停止2S后再中断
}
catch (Exception e)
{
}
t.interrupt();//中断线程
}
}
运行结果:
1、进入run方法
3、休眠被终止了
从以上程序运行的结果可以看出,一个线程启动之后进入了休眠状态,原本是休眠10s后继续运行,但是主方法在线程启动的2s后就将其中断了,休眠一旦中断,就执行catch中的代码,并利用里面的return语句返回程序的调用处。
6. 后台线程
在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 my=new MyThread();
Thread t=new Thread(my,"线程");
t.setDaemon(true);//设置为后台线程
t.start();
}
}
在线程MyThread类中,尽管run()方法中是死循环的方式,但是程序依然可以执行完,因为方法在中死循环的线程操作已经设置为了后台运行了。
7. 线程的优先级
在Java的线程操作中,所有的线程在运行前都会保持在就绪状态,那么此时,哪个线程的优先级高,哪个线程就可能会先被执行。
线程的优先级:
优先级越高,越有可能先执行。
在Java的线程中使用setPriority()方法可以设置一个线程的优先级,在Java的线程中一共有3中优先级:
定义 | 描述 | 表示的常量 |
---|---|---|
public static final MIN_PRIORITY | 最低优先级 | 1 |
public static final NORM_PRIORITY | 中等优先级,线程的默认优先级 | 5 |
public static final MAX_PRIORITY | 最高优先级 | 10 |
不同优先级的线程执行结果。
【测试线程优先级】
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);
}
}
};
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();
}
}
运行结果:
线程B运行,i=0
线程A运行,i=0
线程C运行,i=0
线程B运行,i=1
线程C运行,i=1
线程A运行,i=1
线程B运行,i=2
线程C运行,i=2
线程A运行,i=2
线程B运行,i=3
线程A运行,i=3
线程C运行,i=3
线程B运行,i=4
线程C运行,i=4
线程A运行,i=4
从上面的运行结果可以观察到,线程将根据其优先级的大小来决定哪个线程会先运行,但是读者一定要注意的是,并非线程的优先级越高就一定优先执行,哪个线程先执行将由CPU决定。
主线程的优先级是NORM_PRIORITY
8. 线程的礼让
在线程操作中,也可以使用yield()方法将一个线程的操作暂时让给其他线程执行。
【线程的礼让】
class MyThread implements Runnable
{
public void run(){
for (int i=0;i<5 ;i++ )
{
System.out.println(Thread.currentThread().getName()+"运行-->"+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();
}
}
运行结果:
线程A运行-->0
线程B运行-->0
线程B运行-->1
线程B运行-->2
线程礼让:线程A运行-->1
线程A运行-->2
线程礼让:线程B运行-->3
线程B运行-->4
线程A运行-->3
线程A运行-->4
从结果就可以发现,每当线程满足条件时(i==2),就会将本线程暂停,而让其他线程先执行。
好了,以上就是线程常用的几种操作了。