线程
来源:互联网 发布:爱知科技工资怎么样 编辑:程序博客网 时间:2024/06/05 18:00
我们使用计算机可以同时完成听歌、打印、看电影等活动,这种思想放在java中被称为并发,而将并发完成的每一件事情称为线程。
一、进程与线程
进程是程序的一次动态执行过程,经历了从代码加载、执行到执行完毕的一个完整过程,这个过程也是进程本身从产生、发展到最终消亡的过程。
进程和线程一样都是实现并发的一个基本单位。线程是比进程更小的执行单位,线程是在进程的基础上进行的进一步的划分。所谓的多线程是指一个进程在执行过程中可以产生多个线程,这些线程可以同时存在、同时运行,一个进程可能包含了多个同时执行的线程。所有的线程一定要依附于进程才能够存在,进程一旦消失线程也一定会消失。
二、多线程的实现
java中要想实现多线程的程序,就必须依靠一个线程的主体类,该类可以继承继承java.lang.Thread和实现java.lang.Runnable接口。
实现线程的方式主要有两种:继承java.lang.Thread和实现java.lang.Runnable接口。
2.1继承Thread类实现多线程
java.lang.Thread是一个负责线程操作的类,任何的类只要继承Thread类就可以成为一个线程的主类,主类就有它的使用方法,而线程启动的主方法是需要覆写Thread类中的run()方法实现的。线程主体类的定义格式如下:
class 类名称 extends Thread(){ 属性··· 方法···public void run(){ 线程主体方法; }}
我们来看一个例子:
这里我写了两个类,一个是MyThread继承了Thread类,另一个是调用我们的线程的类。
package com.test2;public class MyThread extends Thread{private String title;public MyThread(String title){this.title=title;}public void run() {for(int x=0;x<5;x++){System.out.println(this.title+"运行,x="+x);}};}
线程类写好后我们看启动线程的类:package com.test2;public class TestDemo {public static void main(String[] args) {MyThread mt1=new MyThread("线程A");MyThread mt2=new MyThread("线程B");MyThread mt3=new MyThread("线程C");mt1.start();mt2.start();mt3.start();}}
程序运行的每一次结果都是不一样的,但一定会是交替出现的才对。如:线程A运行,x=0线程A运行,x=1线程B运行,x=0线程C运行,x=0线程C运行,x=1线程B运行,x=1线程A运行,x=2线程A运行,x=3线程A运行,x=4线程B运行,x=2线程C运行,x=2线程B运行,x=3线程B运行,x=4线程C运行,x=3线程C运行,x=4
注意!!!想在程序中真正启动多线程,必须依靠Thread类的方法public void start(),表示真正启动多线程,调用此方法后会间接调用run方法。
2.2 利用Runnable接口实现多线程
上面使用了Thread类来进行多线程的实现,但是缺点是单继承的问题。所以有了Runnable接口来实现多线程。
格式:
class 类名称 implements Runnable{ 属性··· 方法··· public void run(){ 线程主体;//覆写Runnable接口里的run()方法 }}上面写到启动线程我们需要用start()方法,但是start()方法是依靠的Thread类的,现在我们却使用的是Runnable接口,又该如何启动线程呢?别急,要解决这个问题还是要依靠Thread类完成,在Thread类中定义一个构造方法public Thread(Runnable target),通过此构造方法接收Runnable接口对象,并利用Thread类启动多线程。看例子吧:
MyThreadThread类
package com.test2;public class MyThreadThread implements Runnable{private String title;public MyThreadThread(String title){this.title=title;}@Overridepublic void run() {for(int x=0;x<5;x++){System.out.println(this.title+"运行,x="+x);}}}启动线程类:
package com.test2;public class TestDemoThread {public static void main(String[] args) {MyThreadThread mtt1=new MyThreadThread("线程A");MyThreadThread mtt2=new MyThreadThread("线程B");MyThreadThread mtt3=new MyThreadThread("线程C");//启动线程new Thread(mtt1).start();new Thread(mtt2).start();new Thread(mtt3).start();}}
运行结果和上面一样就不在贴了。
2.3线程的操作状态
要想实现多线程,必须在主线程中创建新的线程对象。任何线程一般具有5中状态:创建、就绪、运行、阻塞和终止。
2.3.1 创建状态
新建线程对象可采用Thread类的构造方法来实现,如Thread thread=new Thread()。创建线程对象后,新的线程对象便处于新建状态,此时,已经有了相应的内存空间和其他资源,但还处于不可运行的状态。
2.3.2 就绪状态
调用start()方法可以启动线程了。线程启动时,即进入就绪状态。此时,线程将进入线程队列排队,等待CPU服务,这表明它已经具备了运行条件。
2.3.3 运行状态
当就绪状态的线程被调用并获得处理器资源时,线程就进入了运行状态。此时,自动调用该线程对象的run()方法。run()方法定义了该线程的操作和功能。
2.3.4 堵塞状态
正在运行的线程在某些情况下,如被人为挂起或需要执行耗时的输入输出操作时,将让出CPU并暂时中止自己的执行,进入堵塞状态。在可执行状态下,如果调用sleep()、suspend()、wait()等方法,线程都将进入堵塞状态。堵塞时,线程不能进入排队队列,只有当引入的堵塞原因被消除后,线程才可以转入就绪状态。
2.3.5 中止状态
线程调用stop()方法或run()方法执行结束后,线程即处于终止状态。此时,线程不具有继续运行的能力。
三、线程的主要操作方法
3.1 线程的命名和取得
线程的运行不可见,每次操作也是无法预料的,想要在程序中操作线程,唯一依靠的就是线程名称,取得和设置线程的名称如下:
public Thread (Runnable target ,String name) 构造 实例化线程对象,接收Runnable接口子类对象,同时设置线程名称
public final void setName(String name) 普通 设置线程名称
public final String getName() 普通 取得线程名称
取得当前线程对象:public static Thread currentThread()
3.2 线程的休眠
Thread类中提供了sleep(long millis)方法令线程开启休眠。
3.3 线程的优先级
如运算符有优先级一样,在线程的操作中同样有着先后操作。
线程在运行前都会保持在就绪状态,之后哪个优先级高哪个就会先执行。
而设置线程的优先级就需要用到Thread类中的下面这些方法和常量:
No.方法和常量类型描述1public static final int MAX_PRIORITY常量最高优先级,数值为102public static final int NORM_PRIORITY常量中等优先级,数值为53public static final int MIN_PRIORITY常量最低优先级,数值为14public final void setPriority(int newPriority)普通设置线程优先级5public final int getPriority();普通取得线程优先级
四、线程的同步与死锁
理解同步的概念:多个操作在同一个时间段内只能有一个线程进行,其他线程要等待此线程完成后才可以继续执行。
如何做到令其他线程在外等待呢?——加锁。
比如你要上洗手间,开门却发现打不开(上了锁),里面正有人在使用该洗手间,你没有办法,只好在门外等待里面的人出来。等锁打开,里面的人出来后,你才可以继续进去。
Java中加锁的方式是:①使用同步代码块;②使用同步方法。两者都要使用synchronized关键字。
4.1使用同步代码块加锁
使用synchronized定义的代码块就是同步代码块。
synchronized(同步对象){ //代码...}
观测上面的代码,括号中必须设置一个同步对象。该对象理解为当前对象this。
4.2使用同步方法
private static final synchronized 方法返回值类型 方法名称(参数) [throws异常]{ [return[返回值]];}
4.3死锁
两个线程都在等待彼此先完成,造成了程序的停滞。
线程间的操作有一个经典案例——生产者消费者。参考这篇文章第7条。(传送门)
五、线程的生命周期
新的方法:(不推荐使用,已经渐渐废除掉了,知道就好)
①suspend()方法:暂时挂起线程
②resume()方法:恢复挂起的线程
③stop():停止线程
正确的停止一个线程的方式使用标志位,定义一个boolean型的flag,然后新建一个方法
public void stop(){ this.flag = false;//修改标志位}
run方法中判断flag进而是否启动线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 做一个合格的程序猿之浅析Spring AOP源码(十八) Spring AOP开发大作战源码解析
- 本人的MSDN文档集合
- 两个栈模拟队列,两个队列模拟栈
- XGBoost-安装(Windows/VS2015)
- 大话设计模式—模板方法模式
- 线程
- Object的clone()方法、深拷贝、浅拷贝
- Windows下IPython的配置安装
- tomcat性能调优 大赞
- 王学岗ListView和源码解析(二)
- onActivityForResult不执行
- 汇编级代码优化
- Mysql To Charts(四)--draw ichartjs
- Kubernetes安装部署