在介绍多线程之前,首先我们要先了解什么叫线程,什么叫进程?

进程和线程介绍

进程其实就是一个应用程序,在我们打开qq,谷歌浏览器,网易云音乐,的时候每打开一个应用程序,就会启动一个进程,那么什么是线程呢?线程其实就是进程中的某一个执行过程,一个进程中可以有多个线程.比如我们打开迅雷软件,它是一个进程,然后我们使用迅雷软件下载文件或某某电影,每一个文件或电影都使用了一个线程,这样可以同时工作,提高效率.

多线程的三种方式

第一种:继承Thread类来使用多线程:

//我们先写一个main方法来调用
public class ThreadDemo01 {
    public static void main(String[] args) {
        System.out.println("main 方法执行");
        CreateDemo01 createDemo = new CreateDemo01();
        createDemo.start();
        System.out.println("main 方法启动子线程");
        for (int i = 0; i < 100; i++) {
            System.out.println("main:" + i);
        }
    }
}
//继承Thread类
class CreateDemo01 extends Thread {
	//重写run方法
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("run:" + i);
        }
    }
}

第二种:实现Runnable接口:

public class ThreadDemo02 {
    public static void main(String[] args) {
        System.out.println("main方法启动");
        CreateDemo02 createDemo = new CreateDemo02();
        Thread thread = new Thread(createDemo);
        thread.start();
        System.out.println("main方法启动子线程");
        for (int i = 0; i < 100; i++) {
            System.out.println("main:" + i);
        }
    }
}
//实现Runnable接口
class CreateDemo02 implements Runnable {
	//重写run方法
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("run:" + i);
        }
    }
}

第三种:匿名内部类:

public class ThreadDemo03 {
    public static void main(String[] args) {
        System.out.println("创建main主线程");
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("run:" + i);
                }
            }
        }).start();
        System.out.println("main方法创建子线程");
        for (int i = 0; i < 100; i++) {
            System.out.println("main:" + i);
        }
    }
}

在这里不多做三种实现的介绍,这需要注意的是run方法和start方法的使用,可以看见上面的三种代码中都是使用了Thread来调用start方法,而不是调用run方法,因为run方法并不是多线程的启动方法,而想要启动多线程需要使用start方法来调用run方法启动,还有一个问题就是实现Runnable接口的时候不能直接调用start方法,需要先定义一个Thread类进行调用start方法.

常用方法

1.currentThread()
返回当前执行的对象的引用
2.getId()
返回当前线程的id,可以使用setId自定义
3.getName()
返回当前线程的name,可以使用setname自定义
4.sleep()
休眠线程,使用毫秒值来表示休眠时间
5.join()
等待线程终止
这几个方法是我认为较为常用的方法,当然还有更多的方法,大家可以参考api.

curentThread()方法和getId及getName

class CreateDemo05 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //获取线程的名字使用getName方法,因为这里是实现Runnable接口,所以无法直接使用getName方法
            //直接继承Thread类的话可以直接使用getName和getId方法
            System.out.println("name:" + Thread.currentThread().getName() + "---run:" + i);
        }
    }
}

public class ThreadDemo05 {
    public static void main(String[] args) {
        CreateDemo05 createDemo05 = new CreateDemo05();
        //实现Runnable接口需要使用到Thread类来调用start方法
        Thread thread = new Thread(createDemo05);
        //这里使用了setName来自定义线程的名字
        thread.setName("ThreadName");
        thread.start();
    }
}

sleep()方法

需要注意的是sleep()在run方法中无法直接抛出异常,需要try…catch来捕捉异常

class CreateDemo04 extends Thread {
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
           	    //sleep里面的参数是毫秒值,代表休眠多少毫秒,这里设置为1秒
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("i:" + i);
        }
    }
}

public class ThreadDemo04 {
    public static void main(String[] args) {
        System.out.println("main方法执行");
        CreateDemo04 createDemo04 = new CreateDemo04();
        createDemo04.start();
        System.out.println("main方法创建子线程");
    }
}

多线程运行状态

1.新建状态,指线程刚刚创建的时候,还没有调用start方法的时候
如:new Thread() 这时候线程还没开始执行,就是新建状态

2.就绪状态,线程调用了start()方法,已启动了线程,并调度了run()方法,当start方法返回后,
现在就处于就绪状态,注意并不是立即就运行的,因为需要等待cpu的调度,如果是单核cpu,
那么就会一个一个的线程去调度,所以可能有多个线程都是就绪状态.

3.运行状态,当cpu调度了线程后,就属于运行状态 真正的开始了执行run()方法

4.阻塞状态,通过调用sleep()方法,或者在I/O被阻塞的操作,锁被其它线程持有,等待触发条件.
这四种状态下的线程属于阻塞状态

5.死亡状态,run()方法正常执行完毕,线程会属于死亡状态,
或者一个未捕捉的异常终止了run方法运行
可以使用isAlive来判断是否死亡,如果是可运行状态或阻塞状态,方法返回true; 如果线程是new状态并且不可运行或线程死亡,则返回false.

下一篇介绍多线程的其他详细内容,如有错误,希望大佬指出,谢谢