线程

  线程是系统调用的最基本单位,多个线程组成进程。电脑中真正执行的线程,我们看到的是进程。

一:定义

  进程的定义:进程是由一个或多个线程组成。

  线程的定义:CPU调度和分配的最基本单位。

二:多线程

  定义:在同一个进程中,同时运行多个线程来完成不同的工作。

  原理:CPU不能同时运行多个线程,在一个时间点系统只能运行一个线程。但是在CPU之中线程之间是高速切换的,人是感觉不到的。所以直观上的感觉是同步执行的。

三:多线程的优点

  01.充分利用CPU的资源   02.提升用户的体验

四:代码实现多线程

  实现步骤:必须继承Thread 或者实现Runnable接口,然后重写run() 方法,在main方法中实例化Thread对象,调用线程类的start()方法启动线程;

五:线程的分类

       用户线程: User Thread :默认我们创建的线程就是!
       守护线程: Daemon Thread: 为其他线程提供服务的! GC线程需要我们手动,setDaemon(true)方法设置。

  注意事项:
    01.默认我们创建的线程就是用户线程!通过Thread类中的setDaemon(true)可以转换成守护线程。
    02.只要有用户线程存在,程序就不会终止,所有的用户线程都执行完毕了, 程序会结束所有的守护线程!JVM停止工作!
    03.setDaemon(true)必须在start()之前
    04.守护线程永远不要访问资源!!!因为守护线程随时都可能销毁!

 1 public class DaemonThread implements Runnable {
 2 
 3     @Override
 4     public void run() {
 5         BufferedWriter bw = null;
 6         Writer out = null;
 7         File file = new File("e:/heihei.txt");
 8         try {
 9             System.out.println("进入了 run()");
10             Thread.sleep(1000); // 保证main先执行完毕
11             // 获取输出流对象
12             out = new FileWriter(file);
13             bw = new BufferedWriter(out);
14             bw.write("守护线程不可能写进去内容!!看不到我!");
15         } catch (IOException e) {
16             e.printStackTrace();
17         } catch (InterruptedException e) {
18             e.printStackTrace();
19         } finally {
20             try {
21                 bw.close();
22                 out.close();
23             } catch (IOException e) {
24                 e.printStackTrace();
25             }
26         }
27     }
28 
29     public static void main(String[] args) {
30         Thread thread = new Thread(new DaemonThread(), "守护线程");
31         // 变成 守护线程
32         // thread.setDaemon(true);
33         thread.start();
34         System.out.println("用户线程===》main结束");
35     }
36 }
守护线程的案例

  01.继承Thread类

 1 /**
 2  * 自己定义的多线程类
 3  * 
 4  * 01.必须继承Thread
 5  * 02.然后重写run() ====>普通的方法
 6  * 03.启动线程调用线程类的start()
 7  */
 8 public class MyThread extends Thread {
 9 
10     /**
11      * 重写了Thread类中的 run()
12      */
13     @Override
14     public void run() {
15         for (int i = 1; i <= 20; i++) {
16             System.out.println(Thread.currentThread().getName() + "在执行==》" + i);
17         }
18     }
19 
20     public static void main(String[] args) {
21         // 创建出来了2个线程对象 然后分别执行 run()
22         MyThread t1 = new MyThread();
23         MyThread t2 = new MyThread();
24         // 分别给两个线程 设置名字
25         t1.setName("线程1");
26         t2.setName("线程2");
27         /*
28          * t1.run(); t2.run(); 直接调用run()其实就是执行普通方法,那么第一个run()没执行完毕,第二个无法执行
29          */
30         // 真正的启动线程,但是线程没有执行! 明明是调用的start(),却是显示的run()方法内容!
31         // 线程的真正执行是run()
32         t1.start();
33         t2.start();
34 
35     }
36 
37 }
继承Thread实现

  02.实现Runnable接口

 1 public class MyRunnable implements Runnable {
 2     /**
 3      * 重写了Runnable类中的 run()
 4      */
 5     @Override
 6     public void run() {
 7         for (int i = 1; i <= 20; i++) {
 8             System.out.println(Thread.currentThread().getName() + "在执行==》" + i);
 9         }
10     }
11 
12     public static void main(String[] args) {
13         // 创建两个线程对象
14         Thread t1 = new Thread(new MyRunnable(), "线程1");
15         Thread t2 = new Thread(new MyRunnable(), "线程2");
16         // 启动线程
17         t1.start();
18         t2.start();
19     }
20 
21 }
实现Runnable接口

  03.实现Callable接口

(一)线程的生命周期   

   01.新生状态     MyThread t1=new MyThread();  
            Thread t2 = new Thread(new RunnableImp());

   02.就绪状态     调用start()方法,线程就绪,等待分配CPU资源。

   03.运行状态     CPU分配时间片给run方法,线程开始执行run方法线程体代码

      04.阻塞状态    sleep() , 休眠(不释放资源) wait() ,等待(释放系统资源)    yield() , 礼让(静态方法,不一定成功。)                                                                                join(),强制执行至结束线程体代码,才会释放资源。

   05.死亡状态   run()执行完毕正常死亡 ,或者是run()执行过程中,出现了异常(java.lang.IllegalThreadStateException)终止运行,线程死亡。

(二)关于start()方法,与run()方法的区别:

   01.start方法是是Thread中的方法,调用后会启动线程至就绪状态,底层会调用run方法。继承Runnable接口没有该方法。

   02.run方法是普通的方法,调用run方法是调用普通方法,不会启动多线程。方法体称之为线程体,当CPU分配时间片给线程时,线程才处于运行状态。

(三)线程的调度方法

  01.设置线程的优先级(有一定的概率调节线程的抢占资源的能力)

 1 /**
 2  * 
 3  * 线程的优先级 Priority
 4  * 默认值是5
 5  * 取值范围是  1-10
 6  * 优先级越高 代表获取CPU资源的概率越高! 并不代表一定高或者一定执行!
 7  * 
 8  */
 9 public class PriorityThread implements Runnable {
10     @Override
11     public void run() {
12         for (int i = 1; i <= 20; i++) {
13             System.out
14                     .println(Thread.currentThread().getName() + "======>" + i);
15         }
16     }
17 
18     public static void main(String[] args) {
19         // 创建两个线程类对象
20         Thread t1 = new Thread(new PriorityThread(), "线程1");
21         Thread t2 = new Thread(new PriorityThread(), "线程2");
22         System.out.println("t1默认的优先级===》" + t1.getPriority());
23         System.out.println("t2默认的优先级===》" + t2.getPriority());
24         // 设置t2的优先级为10 只是一种概率问题 并不能保证 每次都是t2先执行
25         t2.setPriority(10);
26         // 启动线程
27         t1.start();
28         t2.start();
29     }
30 }
setPriority()方法

  02.强制加入join()方法(一定会先执行完毕调用方法的线程)

 1 /**
 2  * 2.Join   加入新线程
 3  *  让新的线程加入进来,新线程执行完毕之后,其他线程才能执行!
 4  */
 5 public class JoinThread implements Runnable {
 6 
 7     @Override
 8     public void run() {
 9         for (int i = 1; i <= 50; i++) {
10             System.out
11                     .println(Thread.currentThread().getName() + "======>" + i);
12         }
13     }
14 
15     // 测试方法
16     public static void main(String[] args) {
17 
18         Thread t1 = new Thread(new JoinThread(), "新线程1");
19         // 启动新线程
20         t1.start();
21         for (int i = 1; i <= 20; i++) { // 主线程的输出
22             System.out
23                     .println(Thread.currentThread().getName() + "======>" + i);
24             if (i == 5) {
25                 try {
26                     System.out.println("T1线程 强制 加入");
27                     t1.join(); // 阻止main线程
28                 } catch (InterruptedException e) {
29                     e.printStackTrace();
30                 }
31             }
32         }
33     }
34 }
join()方法

    03.sleep(long  ms)  Thread类中静态方法,会抛出InterruptedException异常  

 1 /**
 2  * Sleep  线程的休眠     不会释放资源
 3  * 
 4  * sleep(long  ms)  Thread类中方法 
 5        01.线程的休眠,会占着CPU资源不放!其他的线程都无法获取CPU资源!必须等待!
 6        02.long ms指的是在多长时间之后,进入 就绪状态
 7      
 8    wait()是Object类中的方法!
 9             线程wait()的时候,会释放占用的CPU资源!
10         01.其他的线程无需等待!
11         02.必须使用notify唤醒才能进入 就绪状态
12  */
13 public class SleepThread implements Runnable {
14     @Override
15     public void run() {
16         for (int i = 1; i <= 20; i++) {
17             System.out
18                     .println(Thread.currentThread().getName() + "======>" + i);
19             try {
20                 Thread.sleep(1000);// 线程休眠一秒
21             } catch (InterruptedException e) {
22                 e.printStackTrace();
23             }
24         }
25     }
26 
27     public static void main(String[] args) {
28         // 创建线程类对象
29         Thread t = new Thread(new SleepThread(), "休眠的线程");
30         // 线程启动
31         t.start();
32     }
33 }
sleep()方法

   04.sleep 与 wait 方法的区别

    sleep(long ms) Thread类中方法 (ms表示等待的毫秒数)
      01.线程的休眠,会占着CPU资源不放,其他的线程都无法获取CPU资源。必须等待!
      02.long ms指的是在多长时间之后,进入就绪状态;

    wait()是Object类中的方法! 线程wait()的时候,会释放占用的CPU资源!
      01.其他的线程无需等待!
      02.必须使用notify()唤醒才能进入就绪状态;

  05.yield();礼让方法(不一定有效)

 1 public class YieldThread implements Runnable {
 2 
 3     @Override
 4     public void run() {
 5         for (int i = 1; i <= 50; i++) {
 6             System.out
 7                     .println(Thread.currentThread().getName() + "======>" + i);
 8         }
 9     }
10 
11     public static void main(String[] args) {
12         // 创建线程对象
13         Thread t = new Thread(new YieldThread(), "老幼病残线程");
14         // 启动线程
15         t.start();
16         for (int i = 1; i <= 50; i++) {
17             System.out
18                     .println(Thread.currentThread().getName() + "======>" + i);
19             if (i % 5 == 0) {
20                 System.out.println("======main开始礼让了======");
21                 Thread.currentThread().yield(); // 礼让
22             }
23         }
24     }
25 }
yield()礼让方法

  06.设置中断状态。(只是一种标签,不影响线程的运行)

 1 /**
 2  * 设置线程的 中断状态   Interrupt
 3     01.interrupt :      只是设置线程的中断状态,不是终止线程! 线程还会继续执行!
 4     02.isInterrupted:来判断线程是否是 中断状态!
 5     03.interrupted:清除中断状态    interrupted();
 6     04.执行了wait或者sleep,会默认清除中断状态
 7  */
 8 public class InterruptThread implements Runnable {
 9     @Override
10     public void run() {
11         // 判断线程是否是中断状态
12         if (Thread.currentThread().isInterrupted()) {
13             System.out.println("当前线程是 中断状态!");
14         } else {
15             for (int i = 1; i <= 50; i++) {
16                 System.out.println("线程的状态是===》"
17                         + Thread.currentThread().isInterrupted());
18                 System.out.println(Thread.currentThread().getName() + "======>"
19                         + i);
20                 if (i == 25) {
21                     Thread.currentThread().interrupt(); // 线程的中断状态
22                 }
23                 if (i == 40) {
24                     Thread.currentThread().interrupted(); // 清除 线程的中断状态
25                 }
26             }
27         }
28     }
29 
30     public static void main(String[] args) {
31         // 创建线程对象
32         Thread t = new Thread(new InterruptThread(), "中断线程");
33         // 启动线程
34         t.start();
35     }
36 
37 }
中断状态 Interrupt
原文地址:https://www.cnblogs.com/ak666/p/8183865.html