一、基础
线程与进程的
在计算机中,我们把一个任务称为一个进程,浏览器就是一个进程,视频播放器是另一个进程,类似的,音乐播放器和Word都是进程。
某些进程内部还需要同时执行多个子任务。例如,我们在使用Word时,Word可以让我们一边打字,一边进行拼写检查,同时还可以在后台进行打印,我们把子任务称为线程。
进程和线程的关系就是:一个进程可以包含一个或多个线程,但至少会有一个线程。
多线程
Java语言内置了多线程支持:一个Java程序实际上是一个JVM进程,JVM进程用一个主线程来执行main()方法,在main()方法内部,我们又可以启动多个线程。
二、创建多线程的三种方式
1、继承 Thread 类,重写run()方法,run()方法代表线程要执行的任务。
2、实现 Runnable 接口,重写 run()方法,run()方法代表线程要执行的任务。
3、实现 callable 接口,重写 call()方法,call()作为线程的执行体,具有返回值,并且可以对异常进行声明和抛出;使用start()方法来启动线程
1、第一种方法:继承Thread类
Thread是一个线程类,位于java.lang包下
1)构造方法
Thread():创建一个线程对象
Thread(String name):创建一个具有指定名称的线程对象
Thread(Rummable target):创建一个基于Runnable接口实现类的线程对象
Thread(Runnable target,String name):创建一个基于Runnable接口实现类,并且具有指定名称的线程对象。
2)Thread类的常用方法
public void run():线程相关的代码写在该方法中,一般需要重写。
public void start():启动线程的方法 public static void sleep(long m):线程休眠m毫秒的方法
public void join():优先执行调用join()方法的线程。
2、第二种方法:实现Runnable接口
只有一个方法run();
Runnable是Java中用以实现线程的接口
任何实现线程功能的类都必须实现该接口
3、第三种方法:实现callable 接口
1、创建Callable 接口的实现类,并实现 call()方法,该 call()方法将作为线程执行体,并且有返回值。
2、创建Callable 实现类的实例,使用 FutureTask 类来包装Callable 对象,该 FutureTask 对象封装了该Callable 对象的 call()方法的返回值。
3、使用FutureTask 对象作为 Thread 对象的target 创建并启动新线程。
4、调用FutureTask 对象的 get()方法来获得子线程执行结束后的返回值。
三、通过Thread 类创建线程实例
最简单的例子
class MyThread extends Thread{//创建线程类,继承Thread public void run(){ System.out.println(getName()+"该线程正在执行!"); } } public class ThreadTest { /** * 1.主方法main也是一个线程,mt方法也是一个线程,顺序是随机的 * 2.启动线程,线程启动用的是srart,启动的是上面的run方法 * 3.同一个Thread不能重复调用start方法,会抛出IllegalThreadStateException异常 */ public static void main(String[] args) { // System.out.println("主线程1"); MyThread mt=new MyThread(); mt.start();//启动线程 // mt.start(); // System.out.println("主线程2"); } }
四、通过Runnable接口创建线程实例(应用更为广泛)
实现Runnable接口创建线程:
1、创建类PrintRunnable实现接口Runnable;
2、重写run方法;
3、定义Runnable实现类的对象(例:PrintRunnable pr=new PrintRunnable();)
4、通过Thread线程类构造方法传入t1分配一个新的线程对象(例:Thread t1=new Thread(pr) ;)
5、启动线程(例:t1.start();) PS:启动线程只能通过Thread及其子类启动
//通过Runnable接口创建线程 class PrintRunnable implements Runnable { int i = 1;//两个线程共处理10次 @Override public void run() { // int i = 1;//两个线程各处理10次 while (i <= 10) //currentThread当前线程 System.out.println(Thread.currentThread().getName() + "正在运行" + (i++)); } } public class Test { public static void main(String[] args) { //启动线程有3步, //适合多个线程处理同一个资源 PrintRunnable pr = new PrintRunnable(); Thread t1 = new Thread(pr); t1.start(); Thread t2 = new Thread(pr); t2.start(); } }
五、线程的状态和声明周期(sleep&join)
1.线程的状态
新建(New):创建Thread类或者Thread子类的对象时。
可运行(Runnable):创建好的线程调用start方法后,也叫就绪状态。
正在运行(Runnig):处于可运行状态的线程获取CPU的使用权后。
阻塞(Blocked):线程遇到干扰暂停后。
终止(Dead):线程执行完毕或者异常终止。
2.线程的声明周期
stop方法已经弃用。
3、sleep方法
- Thread类的方法:public static void sleep(long millis)
- sleep方法的应用场景:-计时 -控制刷新频率
- sleep方法的作用:在指定的毫秒数内让正在执行的线程休眠(暂停执行)
- 注:在休眠相应时间后,转为可运行状态(而不是正在运行状态),在获取cpu使用权后进入运行状态;
- 这个方法可能会发生InterruptedException异常,需要try-catch捕获。
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);//等待1000毫秒,也就是1秒 } 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(); } }