AI智能
改变未来

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方法

package JAVAADVANCE;public class TestAdvance37TestThread01 {//这里是main方法,这里的代码属于主线程,在主线程中运行public static void main(String[] args) {//新建一个分支线程对象,MyThread myThread=new MyThread();//start开启新的栈空间,启动一个分支线程,启动成功线程自动调用run方法,而直接调用MyThread.run()不会启动多线程myThread.start();//这里的代码运行在主线程中for (int i=0;i<100;i++){System.out.println(\"主线程------->\"+i);}}}class MyThread extends Thread{@Overridepublic void run() {//编写程序,这段代码在分支线程中执行for(int i=0;i<100;i++){System.out.println(\"分支线程------->\"+i);}}}

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

主线程------->91主线程------->92分支线程------->0主线程------->93分支线程------->1主线程------->94主线程------->95

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

package JAVAADVANCE;public class TestAdvance37TestThread02 {public static void main(String[] args) {//创建线程对象,将可运行的对象封装成线程对象Thread t = new Thread(new MyRunnable());t.start();//这里的代码运行在主线程中for (int i = 0; i < 100; i++) {System.out.println(\"主线程------->\" + i);}}}class MyRunnable implements Runnable{@Overridepublic void run() {for(int i=0;i<100;i++){System.out.println(\"分支线程------->\"+i);}}}

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

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

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

package JAVAADVANCE;public class TestAdvance37TestThread03 {public static void main(String[] args) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(\"分支线程------->\" + i);}}});//启动分支线程t.start();for (int i = 0; i < 100; i++) {System.out.println(\"主线程------->\" + i);}}}

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

分支线程------->10主线程------->12分支线程------->11主线程------->13分支线程------->12主线程------->14分支线程------->13

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

(1)优先与缺点:

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

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

(2)实现方式

package JAVAADVANCE;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.Future;import java.util.concurrent.FutureTask;public class TestAdvance37TestThread10 {public static void main(String[] args) {//创建一个未来任务对象,需要黑一个callable接口实现类的对象,这里使用匿名内部类FutureTask task=new FutureTask(new Callable() {@Overridepublic Object call() throws Exception {//call()类似run方法,但是有返回值//模拟行为System.out.println(\"call method begin\");Thread.sleep(1000*10);System.out.println(\"call method end\");int a=100;int b=200;return a+b; //自动装箱,300结果变为Integer}});//创建线程对象Thread t=new Thread(task);//启动线程t.start();//获取t线程的返回结果try {Object obj=task.get();System.out.println(\"线程的执行结果为:\"+obj);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}//main方法这里的程序要想执行必须等待get方法System.out.println(\"hello world\");}}

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

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

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

package JAVAADVANCE;public class TestAdvance37TestThread04 {public static void main(String[] args) {//获取当前线程对象Thread t1=Thread.currentThread();System.out.println(\"main方法下的当前线程名:\"+t1.getName());MyThread t2=new MyThread();//查看线程默认名System.out.println(\"线程默认名:\"+t2.getName());t2.setName(\"ttttt\");System.out.println(\"修改后的线程名:\"+t2.getName());}}

查看执行结果

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

四、线程sleep方法

1、概念:

(1)sleep为静态方法

(2)参数为毫秒

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

2、举例说明sleep方法

package JAVAADVANCE;public class TestAdvance37TestThread05 {public static void main(String[] args) {//让当前进程进入休眠状态,睡眠5秒try {Thread.sleep(1000*5);System.out.println(\"hello world\");} catch (InterruptedException e) {e.printStackTrace();}}}

5秒后控制台打印hello world

3、中止进程的睡眠

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

package JAVAADVANCE;public class TestAdvance37TestThread06 {public static void main(String[] args) {Thread t=new Thread(new MyRunnable2());t.setName(\"t\");t.start();try {Thread.sleep(1000*5);} catch (InterruptedException e) {e.printStackTrace();}//终于线程的睡眠t.interrupt();}}class MyRunnable2 implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+\"---->begin\");try {Thread.sleep(1000*60*60*24*365);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+\"----->end\");}}

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

t---->beginjava.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at JAVAADVANCE.MyRunnable2.run(TestAdvance37TestThread06.java:23)at java.lang.Thread.run(Thread.java:748)t----->endProcess finished with exit code 0

4、强行终止进程执行

package JAVAADVANCE;public class TestAdvance37TestThread07 {public static void main(String[] args) {Thread t=new Thread(new MyRunnable3());t.setName(\"t\");t.start();try {Thread.sleep(1000*5);} catch (InterruptedException e) {e.printStackTrace();}t.stop();}}class MyRunnable3 implements Runnable{@Overridepublic void run() {for(int i=0;i<10;i++){System.out.println(Thread.currentThread().getName()+\"------>\"+i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}

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

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

package JAVAADVANCE;import static java.lang.Thread.sleep;public class TestAdvance37TestThread08 {public static void main(String[] args) {MyRunnable4 r=new MyRunnable4();Thread t=new Thread(r);t.setName(\"t\");t.start();try {sleep(1000*5);} catch (InterruptedException e) {e.printStackTrace();}//什么时候中止t改为falser.run=false;}}class MyRunnable4 implements Runnable{//打一个布尔标记boolean run=true;@Overridepublic void run() {for(int i=0;i<10;i++){if(run){System.out.println(Thread.currentThread().getName()+\"----->\"+i);try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}else {//save保存代码//终止当前线程return;}}}}

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

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

五、线程调度与优先级

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

2、常用方法:

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

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

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

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

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

六、线程安全(重点)

参考下一个章节

七、死锁

1、含义:

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

2、举例:

package JAVAADVANCE;public class TestAdvance37TestThread09 {public static void main(String[] args) {Object o1=new Object();Object o2=new Object();Thread t1=new MyThread1(o1,o2);Thread t2=new MyThread2(o1,o2);t1.start();t2.start();}}class MyThread1 extends Thread{Object o1;Object o2;public MyThread1(Object o1,Object o2){this.o1=o1;this.o2=o2;}public void run(){synchronized (o1){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (o2){}}}}class MyThread2 extends Thread{Object o1;Object o2;public MyThread2(Object o1,Object o2){this.o1=o1;this.o2=o2;}public void run(){synchronized (o2){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (o1){}}}}

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

3、解决方案:

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

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » java进阶(37)–多线程