• java进阶(37)--多线程


    文档目录:

    一、进程与线程

    二、多线程的实现

    三、获取线程名与线程对象

    四、线程sleep方法

    五、线程调度与优先级

    六、线程安全(重点)

    七、死锁

    ---------------------------------------分割线:正文--------------------------------------------------------

    一、进程与线程

    1、基本概念

    进程是一个应用程序。

    线程是一个进程中的执行场景/执行单元。

    一个进程可以启动多个线程

     

    2、举例说明进程与线程、

    java输出helloworld回车,先启动JVM是一个进行,JVM再启动一个主线程调用main方法,同时再启动一个垃圾回收线程负责看护,回收垃圾,至少两个线程并发。

     

    3、进程与线程的关系

    阿里巴巴:进程A

    马云:阿里巴巴的一个线程

    张小龙:阿里巴巴的一个线程

    京东:进程B

    强东:jd的一个线程

    奶茶:jd的一个吸纳还曾

    进程A与B内存独立不共享(阿里与jd资源不共享)

    线程A与线程B:JAVA中堆内存与方法区内存共享,栈内存独立

     

    4、多线程机制的目的

    提高程序的处理效率

     

    二、多线程的实现

    1、第一种实现方式:继承java.lang.Thread方法,并重新run方法

     1 package JAVAADVANCE;
     2 public class TestAdvance37TestThread01 {
     3     //这里是main方法,这里的代码属于主线程,在主线程中运行
     4     public static void main(String[] args) {
     5         //新建一个分支线程对象,
     6        MyThread myThread=new MyThread();
     7        //start开启新的栈空间,启动一个分支线程,启动成功线程自动调用run方法,而直接调用MyThread.run()不会启动多线程
     8         myThread.start();
     9         //这里的代码运行在主线程中
    10         for (int i=0;i<100;i++){
    11             System.out.println("主线程------->"+i);
    12         }
    13     }
    14 }
    15 class MyThread extends Thread{
    16     @Override
    17     public void run() {
    18     //编写程序,这段代码在分支线程中执行
    19         for(int i=0;i<100;i++){
    20             System.out.println("分支线程------->"+i);
    21         }
    22     }
    23 }

    查看执行结果片段:主线程与分支线程是并发的

    1 主线程------->91
    2 主线程------->92
    3 分支线程------->0
    4 主线程------->93
    5 分支线程------->1
    6 主线程------->94
    7 主线程------->95

    2、第二种实现方式:编写一个类,实现java.lang.Runnable接口,实现run方法(建议使用,因为此类还可以继承其他方法)

     1 package JAVAADVANCE;
     2 
     3 public class TestAdvance37TestThread02 {
     4     public static void main(String[] args) {
     5         //创建线程对象,将可运行的对象封装成线程对象
     6         Thread t = new Thread(new MyRunnable());
     7         t.start();
     8         //这里的代码运行在主线程中
     9         for (int i = 0; i < 100; i++) {
    10             System.out.println("主线程------->" + i);
    11         }
    12     }
    13 }
    14 class MyRunnable implements Runnable{
    15     @Override
    16     public void run() {
    17         for(int i=0;i<100;i++){
    18             System.out.println("分支线程------->"+i);
    19         }
    20     }
    21 }

    查看执行结果片段:主线程与分支线程是并发的

    1 分支线程------->54
    2 主线程------->4
    3 主线程------->5
    4 分支线程------->55
    5 主线程------->6
    6 主线程------->7

    3、第三种实现方式:采用匿名内部类方法

     1 package JAVAADVANCE;
     2 
     3 public class TestAdvance37TestThread03 {
     4     public static void main(String[] args) {
     5         Thread t = new Thread(new Runnable() {
     6             @Override
     7             public void run() {
     8                 for (int i = 0; i < 100; i++) {
     9                     System.out.println("分支线程------->" + i);
    10                 }
    11             }
    12         });
    13         //启动分支线程
    14         t.start();
    15         for (int i = 0; i < 100; i++) {
    16             System.out.println("主线程------->" + i);
    17         }
    18     }
    19 }

    查看执行结果片段:主线程与分支线程是并发的

    1 分支线程------->10
    2 主线程------->12
    3 分支线程------->11
    4 主线程------->13
    5 分支线程------->12
    6 主线程------->14
    7 分支线程------->13

    4、第四种实现方式:实现callable接口(JDK8新特性) 

    (1)优先与缺点:

    优点:可以拿到线程的执行结果

    缺点:效率比较低,获取结果时,当前线程受阻塞

    (2)实现方式

     1 package JAVAADVANCE;
     2 
     3 import java.util.concurrent.Callable;
     4 import java.util.concurrent.ExecutionException;
     5 import java.util.concurrent.Future;
     6 import java.util.concurrent.FutureTask;
     7 
     8 public class TestAdvance37TestThread10 {
     9     public static void main(String[] args) {
    10         //创建一个未来任务对象,需要黑一个callable接口实现类的对象,这里使用匿名内部类
    11         FutureTask task=new FutureTask(new Callable() {
    12             @Override
    13             public Object call() throws Exception {
    14                 //call()类似run方法,但是有返回值
    15                 //模拟行为
    16                 System.out.println("call method begin");
    17                 Thread.sleep(1000*10);
    18                 System.out.println("call method end");
    19                 int a=100;
    20                 int b=200;
    21                 return a+b; //自动装箱,300结果变为Integer
    22             }
    23         });
    24         //创建线程对象
    25         Thread t=new Thread(task);
    26         //启动线程
    27         t.start();
    28         //获取t线程的返回结果
    29         try {
    30             Object obj=task.get();
    31             System.out.println("线程的执行结果为:"+obj);
    32         } catch (InterruptedException e) {
    33             e.printStackTrace();
    34         } catch (ExecutionException e) {
    35             e.printStackTrace();
    36         }
    37         //main方法这里的程序要想执行必须等待get方法
    38         System.out.println("hello world");
    39 
    40     }
    41 }

    查看执行结果:hello world在10秒后展示

    call method begin
    call method end
    线程的执行结果为:300
    hello world

     

    三、获取线程名与线程对象

     1 package JAVAADVANCE;
     2 
     3 public class TestAdvance37TestThread04 {
     4     public static void main(String[] args) {
     5         //获取当前线程对象
     6         Thread t1=Thread.currentThread();
     7         System.out.println("main方法下的当前线程名:"+t1.getName());
     8         MyThread t2=new MyThread();
     9         //查看线程默认名
    10         System.out.println("线程默认名:"+t2.getName());
    11         t2.setName("ttttt");
    12         System.out.println("修改后的线程名:"+t2.getName());
    13     }
    14 }

    查看执行结果

    main方法下的当前线程名:main
    线程默认名:Thread-0
    修改后的线程名:ttttt

     

    四、线程sleep方法

    1、概念:

    (1)sleep为静态方法

    (2)参数为毫秒

    (3)作用:让当前线程进入休眠,进入"阻塞状态",放弃占用cpu时间片,让给其他线程使用

    2、举例说明sleep方法

     1 package JAVAADVANCE;
     2 
     3 public class TestAdvance37TestThread05 {
     4     public static void main(String[] args) {
     5         //让当前进程进入休眠状态,睡眠5秒
     6         try {
     7             Thread.sleep(1000*5);
     8             System.out.println("hello world");
     9         } catch (InterruptedException e) {
    10             e.printStackTrace();
    11         }
    12     }
    13 }

    5秒后控制台打印hello world

    3、中止进程的睡眠

     注:run()方法内只能try catch,不能throws,因为子类不能比父类抛出更多的异常

     1 package JAVAADVANCE;
     2 
     3 public class TestAdvance37TestThread06 {
     4     public static void main(String[] args) {
     5         Thread t=new Thread(new MyRunnable2());
     6         t.setName("t");
     7         t.start();
     8         try {
     9             Thread.sleep(1000*5);
    10         } catch (InterruptedException e) {
    11             e.printStackTrace();
    12         }
    13         //终于线程的睡眠
    14         t.interrupt();
    15     }
    16 }
    17 
    18 class MyRunnable2 implements Runnable{
    19     @Override
    20     public void run() {
    21         System.out.println(Thread.currentThread().getName()+"---->begin");
    22         try {
    23             Thread.sleep(1000*60*60*24*365);
    24         } catch (InterruptedException e) {
    25             e.printStackTrace();
    26         }
    27         System.out.println(Thread.currentThread().getName()+"----->end");
    28     }
    29 }

    查看运行结果:sleep5秒后出现异常信息,进程被中止

    t---->begin
    java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
        at JAVAADVANCE.MyRunnable2.run(TestAdvance37TestThread06.java:23)
        at java.lang.Thread.run(Thread.java:748)
    t----->end
    
    Process finished with exit code 0

    4、强行终止进程执行

     1 package JAVAADVANCE;
     2 
     3 public class TestAdvance37TestThread07 {
     4     public static void main(String[] args) {
     5         Thread t=new Thread(new MyRunnable3());
     6         t.setName("t");
     7         t.start();
     8         try {
     9             Thread.sleep(1000*5);
    10         } catch (InterruptedException e) {
    11             e.printStackTrace();
    12         }
    13         t.stop();
    14     }
    15 }
    16 
    17 class MyRunnable3 implements Runnable{
    18     @Override
    19     public void run() {
    20         for(int i=0;i<10;i++){
    21             System.out.println(Thread.currentThread().getName()+"------>"+i);
    22             try {
    23                 Thread.sleep(1000);
    24             } catch (InterruptedException e) {
    25                 e.printStackTrace();
    26             }
    27         }
    28     }
    29 }

    stop方法的缺点:容易丢失数据,直接将线程杀死

    5、合理的终止一个线程的执行

     1 package JAVAADVANCE;
     2 
     3 import static java.lang.Thread.sleep;
     4 
     5 public class TestAdvance37TestThread08 {
     6     public static void main(String[] args) {
     7         MyRunnable4 r=new MyRunnable4();
     8         Thread t=new Thread(r);
     9         t.setName("t");
    10         t.start();
    11         try {
    12             sleep(1000*5);
    13         } catch (InterruptedException e) {
    14             e.printStackTrace();
    15         }
    16         //什么时候中止t改为false
    17         r.run=false;
    18     }
    19 }
    20 
    21 class MyRunnable4 implements Runnable{
    22     //打一个布尔标记
    23     boolean run=true;
    24     @Override
    25     public void run() {
    26 
    27             for(int i=0;i<10;i++){
    28             if(run){
    29                 System.out.println(Thread.currentThread().getName()+"----->"+i);
    30                 try {
    31                     sleep(1000);
    32                 } catch (InterruptedException e) {
    33                     e.printStackTrace();
    34                 }
    35             }
    36 
    37         else {
    38             //save保存代码
    39             //终止当前线程
    40             return;
    41             }
    42         }
    43     }
    44 }

    查看执行结果,5秒后执行结果。

    t----->0
    t----->1
    t----->2
    t----->3
    t----->4

     

    五、线程调度与优先级

    1、分两种:抢占式调度模型与均分式调度模型,java属于前者

    2、常用方法:

    (1)设置线程的优先级:void setPrority()

    (2)获取线程的优先级:int getPrority()

    优先级分:1,5,10(最高)

    (3)进程让位:static void yield()

    (4)合并线程程:t.join() //当前线程阻塞,t线程加入当前线程中

     

    六、线程安全(重点)

    参考下一个章节

     

    七、死锁

     1、含义:

    不出现异常,也不会出现错误,程序僵持,难以调试

    2、举例:

     1 package JAVAADVANCE;
     2 
     3 public class TestAdvance37TestThread09 {
     4     public static void main(String[] args) {
     5         Object o1=new Object();
     6         Object o2=new Object();
     7         Thread t1=new MyThread1(o1,o2);
     8         Thread t2=new MyThread2(o1,o2);
     9         t1.start();
    10         t2.start();
    11     }
    12 }
    13 class MyThread1 extends Thread{
    14     Object o1;
    15     Object o2;
    16     public MyThread1(Object o1,Object o2){
    17         this.o1=o1;
    18         this.o2=o2;
    19     }
    20     public void run(){
    21         synchronized (o1){
    22             try {
    23                 Thread.sleep(1000);
    24             } catch (InterruptedException e) {
    25                 e.printStackTrace();
    26             }
    27             synchronized (o2){}
    28         }
    29     }
    30 }
    31 class MyThread2 extends Thread{
    32     Object o1;
    33     Object o2;
    34     public MyThread2(Object o1,Object o2){
    35         this.o1=o1;
    36         this.o2=o2;
    37     }
    38     public void run(){
    39         synchronized (o2){
    40             try {
    41                 Thread.sleep(1000);
    42             } catch (InterruptedException e) {
    43                 e.printStackTrace();
    44             }
    45             synchronized (o1){}
    46         }
    47     }
    48 }

    程序运行一直不会结束也没有返回

    3、解决方案:

    程序编写使用时尽量避免synchronized 方法嵌套使用

  • 相关阅读:
    sizeof,终极无惑(上)
    send,recv,sendto,recvfrom
    【问卷调查】社团对海大学生成长的影响研究(及部分调查结果)
    Opencv cvCircle函数
    墨菲定律、二八法则、马太效应、手表定理、“不值得”定律、彼得原理、零和游戏、华盛顿合作规律、酒与污水定律、水桶定律、蘑菇管理原理、钱的问题、奥卡姆剃刀等13条是左右人生的金科玉律
    C#操作Excel文件(读取Excel,写入Excel)
    秋风秋雨愁煞人
    Java Applet读写client串口——终极篇
    数据库索引的作用和长处缺点
    EasyARM i.mx28学习笔记——开箱试用总结
  • 原文地址:https://www.cnblogs.com/mrwhite2020/p/14587525.html
Copyright © 2020-2023  润新知