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 方法嵌套使用

原文地址:https://www.cnblogs.com/mrwhite2020/p/14587525.html