所谓的线程就是程序的执行线路。平时我们所写的程序几乎都是单线程的,即程序的执行路径只有一个。但是,在许多应用中单线程是不足以满足我们的要求的。比如:mp3中的功能,如果用单线程去实现,只能播完歌曲之后再显示歌词或者其他,显然不行,我们要求的是边播放歌曲边滚动歌词。这就要用到了我们的多线程,以达到多个功能并发执行。
在我们平时的程序运行时,主要自启动了两个线程:
◆main主线程,调用main方法,执行main方法
◆GC线程:垃圾回收机制,主要用于main线程运行时运行,回收程序之中产生的垃圾
一:线程的构造
1:继承自Thread的线程类 线程名称 = new 继承自Thread的线程类();-->创建了一个继承自Thread的线程类
2:Thread 线程名称 = new Thread (实现了Runnable接口的线程类);-->创建一个已经实现了Runnable接口的线程类
二:如何写多线程?
1:继承自Thread类,重写run方法,然后调用Thread的start方法启动这个新线程
|
结果:
|
结果分析:从结果中可以发现,每次运行这个程序,结果可能不唯一,这是因为程序的执行需要CPU参与, 谁得到了执行权,谁的线程可以运行。main线程和自己创建的线程之间交替进行,也可以说是一种乱序执行,这就是我们所说的多线程之间的乱序执行,那单线程怎么执行的呢?
单线程也就是我们平时所编写的普通程序,如下:
|
结果:
|
结果分析:细心的会发现,这个程序只和上边的那个程序有一句之差,而仅仅是这一句之差,让他变成了单线程,这个程序无论执行多少次,结果只有这一个,这就说明:单线程内部顺序执行。
2:实现Runnable接口,实现接口中的run方法,创建对象,作为Thread构造的参数,调用thread的start方法启动一个新线程。
public class MyRunnable {
public static void main(String[] args) {
MyRun m = new MyRun();//创建实现Runnable接口线程的对象
Thread th = new Thread(m);//作为参数传递给线程
th.start();//线程的启动
for(int i = 0;i<100;i++){
System.out.println("main-->"+(i+1));
}
}
}
class MyRun implements Runnable{//线程的第二种创建方法,实现Runnable接口
@Override
public void run() {
for(int i = 0;i<100;i++){
System.out.println("run-->"+(i+1));
}
}
}
结果:结果仍然同第一种创建线程的乱序结果(因为是乱序,结果不唯一,可自行试试)
三:线程的常用方法
1:start():启动一个新线程,如“线程.start()”这样使用
2:run():创建线程时,要重写的方法,也是线程启动后运行的方法
3:Thread.currentThread():获得当前线程
4:setName(String name):设置线程名称,也可以在创建实现Runnable接口的类对象的参数中传递。
5:getName():获得线程名称,主线程的名字默认为main,其余线程的默认名字形式为:Thread-0,Thread-1,Thread-2...
|
结果:图中的结果只是截取的,这里要说明的是以上5个方法的使用。任然是乱序执行。
|
6:getPriority()、setPriority():得到和设置线程的优先级。优先级范围:1-10。默认为5。优先级也就是谁的优先级高谁就有更大的可能性运行,所以低优先级的线程并不是不执行,只是没有那么大的机会被执行。在资源不足的情况下有所体现。
|
结果:可以从结果中看出线程0的优先级高,当他执行到83时,线程1才执行到73。结果仍为乱序。
|
7:sleep():让线程休眠(停止运行)一段时间
|
执行效果:线程每隔1秒输出一个数,直到输出到100为止。
8:join():当线程A运行的时候,若线程Bjoin() 进来的话,则暂停A的执行,先执行B,直到B执行结束之后,才继续开始A的执行。
|
结果:
|
结果分析:这个程序如果去掉try-catch块中的内容,执行效果和第二个大问题中的第一点一样,应为乱序执行,而加入了join方法之后导致,自己创建的线程先执行,执行结束后才执行main线程。
9:yield():让位,我把执行权先让出来,大家抢,谁抢到了谁执行,抢不过我,就我执行。
|
结果:图中结果为截取的。
|
结果分析:线程让位了一下,导致程序结果中的一段如图所示,说明在某一时刻,main线程抢过了自己创建线程的执行权。
10:setDaemon(boolean bool):将线程设置为守护线程。守护线程一般用于为其他线程提供服务。如GC是一个典型的守护线程。守护线程的特点是:他会随着其他非守护线程结束而结束,且只能在调用start方法之前使用。isDaemon()方法用于判断一个线程是不是守护线程。
|
结果:
|
结果分析:图中的结果是因为守护线程随着主线程的运行而运行,而主线程运行结束之后,通知虚拟机,我结束了,而在通知的这一段时间之内,守护线程又执行了一会,说以就没有马上结束。
转载于:https://blog.51cto.com/cinderella7/1266163