线程简单的来说就是执行的程序,一个进程中可以有多个线程同时进行。
线程的创建有两种方法,一种是创建一个Thread类,或者是一个Thread子类的对象,另一种是创建一个实现Runnable接口的类的对象
Thread类是一个线程类,位于java.lang包中。
几种常见的构造方法:
Thread类的常用方法:
class MyThread extends Thread{
public void run(){
System.out.println(getName()+"该线程正在执行!");
}
}
public class ThreadTest {
public static void main(String[] args) {
//System.out.println("主线程1");
MyThread mt=new MyThread();
mt.start();//启动线程
mt.start();
//System.out.println("主线程2");
}
}
根据上述代码可以看到,当一个类继承自Thread类就是一个线程类,在这个类中将线程相关的代码都写在run()这个方法中,然后在主函数中创建这个类对象并且调用start()方法就可以启动线程了。当然一个线程只能有一个启动线程方法。
需要注意的是线程的执行程序是随机的。
class MyThread extends Thread{
public MyThread(String name){
super(name);
}
public void run(){
for(int i=1;i<=10;i++){
System.out.println(getName()+"正在运行"+i);
}
}
}
public class ThreadTest {
public static void main(String[] args) {
MyThread mt1=new MyThread("线程1");
MyThread mt2=new MyThread("线程2");
mt1.start();
mt2.start();
}
}
在上面这个代码中线程1和线程2的执行顺序是随机的。
线程的执行的随机性其实是由线程之间竞争CPU资源引起的。
public MyThread(String name){
super(name);
}
这个方法实现了对线程的名称指定
sleep方法
class MyThread implements Runnable{
@Override
public void run() {
for(int i=1;i<=30;i++){
System.out.println(Thread.currentThread().getName()+"执行第"+i+"次!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class SleepDemo {
public static void main(String[] args) {
MyThread mt=new MyThread();
Thread t=new Thread(mt);
t.start();
Thread t1=new Thread(mt);
t1.start();
}
}
上面这个代码:Thread.sleep(1000);实现了线程的休眠,sleep里面是以毫秒为单位的,1000ms就是一秒,每休眠1点多秒就执行下一个线程。由于sleep()这个方法在Thread类中是静态方法,因此可以直接用类名调用。
Runnable接口
以Runnable接口实现线程
因为Java不支持多继承,而又不打算重写Thread类方法时就用接口来实现线程。
class PrintRunnable implements Runnable {
int i = 1;
@Override
public void run() {
while (i <= 10)
System.out.println(Thread.currentThread().getName() + "正在运行" + (i++));
}
}
public class Test {
public static void main(String[] args) {
PrintRunnable pr = new PrintRunnable();
Thread t1 = new Thread(pr);
t1.start();
//PrintRunnable pr1 = new PrintRunnable();
Thread t2 = new Thread(pr);
t2.start();
}
}
如代码所示,Runnable接口来创建线程的时候,需要在新建的类中实现Runnable这个接口。并且只有一个run()方法。任何实现线程功能的类都必须实现该接口。并且与继承自Thread类相比,在启动线程时创建类的对象再新建一个Thread类对象,然后再调用start()方法。
PrintRunnable pr = new PrintRunnable(); Thread t1 = new Thread(pr); t1.start();
我们知道线程有五个状态,分别是新建,可运行,正在运行,阻塞,终止这五个状态。因而演变出了生命周期。
线程的生命周期及相互装换
新建状态到可运行状态可以用start()方法来实现
可运行状态到获得CPU使用权限就变成正在运行状态,正在运行状态如果时间片运行完或者通过yield()方法就会变成可运行状态。
正在运行状态通过join()方法,wait()方法,sleep()方法,I/O请求变成阻塞状态
简单介绍一下Thread类中join()方法的作用是等待调用该方法的线程结束后才能执行
class MyThread extends Thread{
public void run(){
for(int i=1;i<=500;i++)
System.out.println(getName()+"正在执行"+i+"次!");
}
}
public class JoinDemo {
public static void main(String[] args) {
MyThread mt=new MyThread();
mt.start();
try {
mt.join(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i=1;i<=20;i++){
System.out.println("主线程运行第"+i+"次!");
}
System.out.println("主线程运行结束!");
}
}
可以看到在上述代码中只有当mt执行一秒之后才会结束这个进程,执行其余进程。
介绍一下线程优先级吧
Java为线程类提供了10个优先级,用整数1-10来表示,超过范围会抛出异常。默认优先级是5
三个优先级常量
MAX_PRIORITY:表示最高级10
MIN_PRIORITY:表示最低级1
NORM_PRIORITY:表示默认级5
线程优先级的相关方法
class MyThread extends Thread{
private String name;
public MyThread(String name){
this.name=name;
}
public void run(){
for(int i=1;i<=50;i++){
System.out.println("线程"+name+"正在运行"+i);
}
}
}
public class PriorityDemo {
public static void main(String[] args) {
//获取主线程的优先级
int mainPriority=Thread.currentThread().getPriority();
//System.out.println("主线程的优先级为:"+mainPriority);
MyThread mt1=new MyThread("线程1");
MyThread mt2=new MyThread("线程2");
//mt1.setPriority(10);
mt1.setPriority(Thread.MAX_PRIORITY);
mt2.setPriority(Thread.MIN_PRIORITY);
mt2.start();
mt1.start();
//System.out.println("线程1的优先级为:"+mt1.getPriority());
}
}