多线程:
1. 介绍:
-
什么是进程,什么是线程:
进程是一个应用程序,线程是一个进程中的执行场景或执行单元,一个进程可以启动多个线程。java中之所以有多线程机制,目的是为了提高程序的处理效率。
-
在java语言中,堆内存和方法区内存共享,但是栈内存独立,一个线程一个栈。
-
使用了多线程机制之后,main方法结束,程序可能也不会结束。main方法结束只是主线程结束了,主栈空了,其它的栈(线程)可能还在压栈弹栈。
2. 创建线程的方式:
-
在java语言中,实现线程一般有两种方式:
-
第一种方式:
-
编写一个类,直接继承java.lang.Thread,重写run()方法。
-
创建分线程对象,调用start()方法。
-
start()方法作用:启动一个分支线程,在JVM中开辟一个新的栈空间,这段代码任务完成之后,瞬间就结束了。
-
启动成功的线程会自动调用run方法,并且run方法在分支栈的底部(压栈)。run方法在分支栈的栈底部,main方法在主线程的栈底部。run和main是平级的。
-
//定义线程类 public class MyThread extends Thread{ //重写run方法 public void run(){ } } //创建线程对象 MyThread t=new MyThread(); //启动线程 t.start();
-
-
第二种方式:
-
编写一个类,实现java.lang.Runnable接口,实现run方法。比较常用。
-
//定义线程类 public class RunnableTest implements Runnable{ //重写run方法 public void run(){ } } //创建一个可运行的对象 RunnableTest rt=new RunnableTest(); //将一个可运行的对象封装成一个线程对象 Thread th=new Thread(rt); //启动线程 th.start();
-
-
采用匿名内部类方式:
public class ThreadTest04 { public static void main(String[] args) { //采用匿名内部类方式,创建线程对象 Thread t=new Thread(new Runnable() { @Override public void run() { for (int i=1;i<101;i++){ System.out.println("分支线程-->"+i); } } }); //启动线程 t.start(); for (int i=1;i<101;i++){ System.out.println("main-->"+i); } } }
-
3. 线程的生命周期图:
4. 线程的常见方法:
1. 获取当前线程对象
void setName(String name); //修改线程名字
String getName() ; //获取线程名称,默认为Thread-0
static Thread currentThread(); //返回当前线程对象
-
代码演示:
public class ThreadTest05 { public static void main(String[] args) { //创建线程对象 MyThread2 t1=new MyThread2(); // t.setName("xiaoma"); //获取线程的名字 String tName=t1.getName(); System.out.println(tName); MyThread2 t2=new MyThread2(); System.out.println(t2.getName()); //启动线程 t1.start(); System.out.println(Thread.currentThread().getName()); } } class MyThread2 extends Thread{ @Override public void run() { for (int i=0;i<100;i++){ //当t1线程执行run方法,那么当前线程就是t1 //当t2线程执行run方法,那么当前线程就是t2 Thread currentThread=Thread.currentThread(); System.out.println(currentThread.getName()+"---->"+i); //Thread-0--->1 } } }
2 . sleep()方法:
-
关于线程的sleep()方法:
//1. 静态方法: Thread.sleep(1000); //2. 参数是毫秒 //3. 作用:让当前线程进入休眠状态,进入“堵塞状态”,放弃占用CPU时间片,让给其他线程使用 //4. Thread.sleep()方法,可以做到间隔特定的时间,去执行一段特定的代码,每隔多久执行一次 static void sleep(long millis);
-
代码演示:
/* 关于线程的sleep()方法 * */ public class ThreadTest06 { public static void main(String[] args) { /* try { //让当前线程进入休眠,睡眠5秒 Thread.sleep(1000 *5); } catch (InterruptedException e) { e.printStackTrace(); } //5秒之后执行这里代码 System.out.println("xiaoma");*/ for(int i=0;i<10;i++){ //每隔一秒,输出一次 System.out.println(Thread.currentThread().getName()+"--->"+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
1. 关于sleep()方法的面试题:
-
问题:这行代码会让线程t进入休眠状态嘛?
不会,sleep()是静态方法和t线程没关系,在执行的时候还是会转为Thread.sleep(1000*5)。
这行代码的作用是:让当前线程进入休眠,也就是说让main线程进入休眠。
public class ThreadTest07 {
public static void main(String[] args) {
//创建线程对象
Thread t=new MyThread3();
t.setName("t");
t.start();
//调用sleep()方法
try {
//问题:这行代码会让线程t进入休眠状态嘛? 不会
//sleep()是静态方法和t线程没关系
// 在执行的时候还是会转为Thread.sleep(1000*5)
//这行代码的作用是:让当前线程进入休眠,也就是说让main线程进入休眠
t.sleep(1000*5);
} catch (InterruptedException e) {
e.printStackTrace();
}
//5秒之后这里才会执行
System.out.println("hello world");
}
}
class MyThread3 extends Thread{
public void run(){
for (int i=0;i<10000;i++){
System.out.println(Thread.currentThread().getName()+"--->"+i);
}
}
}
3. 唤醒线程 interrupted():
-
void interrupt() //依靠了java的异常处理机制,终断睡眠,会打印出异常信息
-
代码演示:
/* sleep睡眠太久了,如何唤醒一个正在睡眠的线程。 * */ public class ThreadTest08 { public static void main(String[] args) { Thread t=new Thread(new MyRunnable2()); t.setName("t"); t.start(); //希望5秒之后t线程醒来 try { Thread.sleep(1000*5); } catch (InterruptedException e) { e.printStackTrace(); } //中断t线程的线程(这种终断睡眠的方式,依靠了java的异常处理机制。) t.interrupt(); //干扰 } } class MyRunnable2 implements Runnable{ //重点:run()当中的异常不能throws ,只能try catch //因为run()方法在父类中没有抛出任何异常,子类不能比父类抛出更多的异常 @Override public void run() { System.out.println(Thread.currentThread().getName()+"---> begin"); try { // 睡眠1年 Thread.sleep(1000*60*60*