彻底搞懂java多线程(一)-pg电子游戏官网

热度:1℃ 发布时间:2022-01-21 17:12:04
目录java多线程线程的创建线程常用方法线程的终止1.自定义实现线程的终止2.使用thread的interrupted来中断3.thraed.interrupted()方法和threaed.currentthread().interrupt()的区别线程的状态线程的优先级守护线程线程组线程安全问题volatile关键字总结

java多线程

线程的创建

1.继承thread

2.实现runnable

3.实现callable

使用继承thread类来开发多线程的应用程序在设计上是有局限性的,因为java是单继承。

继承thread类

public class threaddemo1 { // 继承thread类 写法1 static class mythread extends thread{ @override public void run() { //要实现的业务代码 } } // 写法2 thread thread = new thread(){ @override public void run() { //要实现的业务代码 } };}

实现runnable接口

//实现runnable接口 写法1class myrunnable implements runnable{ @override public void run() { //要实现的业务代码 }}//实现runnable接口 写法2 匿名内部类class myrunnable2 { public static void main(string[] args) { thread thread = new thread(new runnable() { @override public void run() { //要实现的业务代码 } }); }}

实现callable接口(callable futuretask 创建带有返回值的线程)

package threaddeom;import .util.concurrent.callable;import java.util.concurrent.executionexception;import java.util.concurrent.futuretask;/** * user:ypc; * date:2021-06-11; * time: 17:34; *///创建有返回值的线程 callable futurepublic class threaddemo2 { static class mycallable implements callable{ @override public integer call() throws exception { return 0; } } public static void main(string[] args) throws executionexception, interruptedexception { //创建callable子对象 mycallable mycallable = new mycallable(); //使用futuretask 接受 callable futuretask futuretask = new futuretask<>(mycallable); //创建线程并设置任务 thread thread = new thread(futuretask); //启动线程 thread.start(); //得到线程的执行结果 int num = futuretask.get(); }}

也可以使用lambda表达式

class threaddemo21{ //lambda表达式 thread thread = new thread(()-> { //要实现的业务代码 });}

thread的构造方法

彻底搞懂java多线程(一)

线程常用方法

获取当前线程的引用、线程的休眠

class main{ public static void main(string[] args) throws interruptedexception { thread.sleep(1000); //休眠1000毫秒之后打印 system.out.println(thread.currentthread()); system.out.println(thread.currentthread().getname()); }}

彻底搞懂java多线程(一)

package threaddeom;/** * user:ypc; * date:2021-06-11; * time: 18:38; */public class threaddemo6 { public static void main(string[] args) throws interruptedexception { thread thread = new thread(new runnable() { @override public void run() { system.out.println("线程的id:" thread.currentthread().getid()); system.out.println("线程的名称:" thread.currentthread().getname()); system.out.println("线程的状态:" thread.currentthread().getstate()); try { thread.sleep(1000); } catch (interruptedexception e) { e.printstacktrace(); } } },"线程一"); thread.start(); thread.sleep(100); //打印线程的状态 system.out.println("线程的状态:" thread.getstate()); system.out.println("线程的优先级:" thread.getpriority()); system.out.println("线程是否存活:" thread.isalive()); system.out.println("线程是否是守护线程:" thread.isdaemon()); system.out.println("线程是否被打断:" thread.isinterrupted()); }}

彻底搞懂java多线程(一)

线程的等待

假设有一个坑位,thread1 和 thread2 都要上厕所。一次只能一个人上,thread2只能等待thread1使用完才能使用厕所。就可以使用join()方法,等待线程1执行完,thread2在去执行。👇

package threaddeom;/** * user:ypc; * date:2021-06-12; * time: 10:48; */public class threaddemo13 { public static void main(string[] args) throws interruptedexception { runnable runnable = new runnable() { @override public void run() { system.out.println(thread.currentthread().getname() "🚾"); try { thread.sleep(1000); } catch (interruptedexception e) { e.printstacktrace(); } system.out.println(thread.currentthread().getname() "出来了"); } }; thread t1 = new thread(runnable,"thread1"); t1.start(); //t1.join(); thread t2 = new thread(runnable,"thread2"); t2.start(); }}

彻底搞懂java多线程(一)

没有join()显然是不行的。加上join()之后:

彻底搞懂java多线程(一)

线程的终止1.自定义实现线程的终止

package threaddeom;/** * user:ypc; * date:2021-06-12; * time: 9:59; */public class threaddemo11 { private static boolean flag = false; public static void main(string[] args) throws interruptedexception { thread thread = new thread(new runnable() { @override public void run() { while (!flag){ system.out.println("我是 : " thread.currentthread().getname() ",我还没有被interrupted呢"); try { thread.sleep(100); } catch (interruptedexception e) { e.printstacktrace(); } } system.out.println("我是 " thread.currentthread().getname() ",我被interrupted了"); } },"thread"); thread.start(); thread.sleep(300); flag = true; }}

彻底搞懂java多线程(一)

2.使用thread的interrupted来中断

package threaddeom;/** * user:ypc; * date:2021-06-12; * time: 9:59; */public class threaddemo11 {// private static boolean flag = false; public static void main(string[] args) throws interruptedexception { thread thread = new thread(new runnable() { @override public void run() { while (!thread.interrupted()){ system.out.println("我是 : " thread.currentthread().getname() ",我还没有被interrupted呢"); try { thread.sleep(100); } catch (interruptedexception e) {// e.printstacktrace(); break; } } system.out.println("我是 " thread.currentthread().getname() ",我被interrupted了"); } },"thread"); thread.start(); thread.sleep(300); thread.interrupt();// flag = true; }}

彻底搞懂java多线程(一)

3.thraed.interrupted()方法和threaed.currentthread().interrupt()的区别

thread.interrupted()方法第一次接收到终止的状态后,之后会将状态复位,thread.interrupted()是静态的,是全局的。

threaed.currentthread().interrupt()只是普通的方法。

thraed.interrupted()方法

package threaddeom;/** * user:ypc; * date:2021-06-12; * time: 10:32; */public class threaddemo12 { public static void main(string[] args) throws interruptedexception { thread thread = new thread(() ->{ for (int i = 0; i < 10; i ) { system.out.println(thread.interrupted()); } }); thread.start(); thread.interrupt(); }}

彻底搞懂java多线程(一)

threaed.currentthread().interrupt()

package threaddeom;/** * user:ypc; * date:2021-06-12; * time: 10:32; */public class threaddemo12 { public static void main(string[] args) throws interruptedexception { thread thread = new thread(() ->{ for (int i = 0; i < 10; i ) {// system.out.println(thread.interrupted()); system.out.println(thread.currentthread().isinterrupted()); } }); thread.start(); thread.interrupt(); }}

彻底搞懂java多线程(一)

yield()方法

让出cpu的执行权

package threaddeom;/** * user:ypc; * date:2021-06-12; * time: 11:47; */public class threaddemo15 { public static void main(string[] args) { thread thread1 = new thread(() -> { for (int i = 0; i < 100; i ) { thread.yield(); system.out.println("thread1"); } }); thread1.start(); thread thread2 = new thread(() -> { for (int i = 0; i < 100; i ) { system.out.println("thread2"); } }); thread2.start(); }}

彻底搞懂java多线程(一)

线程的状态

彻底搞懂java多线程(一)

打印出线程的所有的状态,所有的线程的状态都在枚举中。👇

package threaddeom;/** * user:ypc; * date:2021-06-12; * time: 11:06; */public class threaddemo14 { public static void main(string[] args) { for (thread.state state: thread.state.values()) { system.out.println(state); } }}

彻底搞懂java多线程(一)

new 创建了线程但是还没有开始工作 runnable 正在java虚拟机中执行的线程 blocked 受到阻塞并且正在等待某个监视器的锁的时候所处的状态 waitting 无限期的等待另一个线程执行某个特定操作的线程处于这个状态 time_waitting 有具体等待时间的等待 terminated 已经退出的线程处于这种状态

package threaddeom;/** * user:ypc; * date:2021-06-12; * time: 11:06; */class testthreaddemo{ public static void main(string[] args) throws interruptedexception { thread thread = new thread(new runnable() { @override public void run() { try { thread.sleep(2000); } catch (interruptedexception e) { e.printstacktrace(); } } }); system.out.println(thread.getstate()); thread.start(); system.out.println(thread.getstate()); thread.sleep(100); system.out.println(thread.getstate()); thread.join(); system.out.println(thread.getstate()); }}

彻底搞懂java多线程(一)

线程的优先级

在java中线程 的优先级分为1 ~ 10 一共十个等级

package threaddeom;/** * user:ypc; * date:2021-06-11; * time: 21:22; */public class threaddemo9 { public static void main(string[] args) { for (int i = 0; i < 5; i ) { thread t1 = new thread(new runnable() { @override public void run() { system.out.println("t1"); } }); //最大优先级 t1.setpriority(10); t1.start(); thread t2 = new thread(new runnable() { @override public void run() { system.out.println("t2"); } }); //最小优先级 t2.setpriority(1); t2.start(); thread t3 = new thread(new runnable() { @override public void run() { system.out.println("t3"); } }); t3.setpriority(1); t3.start(); } }}

彻底搞懂java多线程(一)

线程的优先级不是绝对的,只是给程序的建议。

线程之间的优先级具有继承的特性,如果a线程启动了b线程,那么b的线程的优先级与a是一样的。👇

package threaddeom;/** * user:ypc; * date:2021-06-11; * time: 20:46; */class threada extends thread{ @override public void run() { system.out.println("threada优先级是:" this.getpriority()); threadb threadb = new threadb(); threadb.start(); }}class threadb extends threada{ @override public void run() { system.out.println("threadb的优先级是:" this.getpriority()); }}public class threaddemo7 { public static void main(string[] args) { system.out.println("main线程开始的优先级是:" thread.currentthread().getpriority()); system.out.println("main线程结束的优先级是:" thread.currentthread().getpriority()); threada threada = new threada(); threada.start(); }}

彻底搞懂java多线程(一)

再看👇

package threaddeom;/** * user:ypc; * date:2021-06-11; * time: 20:46; */class threada extends thread{ @override public void run() { system.out.println("threada优先级是:" this.getpriority()); threadb threadb = new threadb(); threadb.start(); }}class threadb extends threada{ @override public void run() { system.out.println("threadb的优先级是:" this.getpriority()); }}public class threaddemo7 { public static void main(string[] args) { system.out.println("main线程开始的优先级是:" thread.currentthread().getpriority()); thread.currentthread().setpriority(9); system.out.println("main线程结束的优先级是:" thread.currentthread().getpriority()); threada threada = new threada(); threada.start(); }}

结果为👇

彻底搞懂java多线程(一)守护线程

java中有两种线程:一种是用户线程,一种就是守护线程。

什么是守护线程?守护线程是一种特殊的线程,当进程中不存在用户线程的时候,守护线程就会自动销毁。典型的守护线程就是垃圾回收线程,当进程中没有了非守护线程,则垃圾回收线程也就没有存在的必要了。

daemon线程的作用就是为其他线程的运行提供便利的。👇

package threaddeom;/** * user:ypc; * date:2021-06-11; * time: 21:06; */public class threaddemo8 { static private int i = 0; public static void main(string[] args) throws interruptedexception { thread thread = new thread(new runnable() { @override public void run() { while (true){ i ; system.out.println(i); try { thread.sleep(1000); } catch (interruptedexception e) { e.printstacktrace(); } } } }); //设置守护线程 thread.setdaemon(true); thread.start(); thread.sleep(5000); system.out.println("我是守护线程thread 当用户线程执行完成后 我也就销毁了😭哭了"); }}

彻底搞懂java多线程(一)

注意:守护线程的设置必须放在start()之前,否则就会报错。

彻底搞懂java多线程(一)

在守护线程中创建的线程默认也是守护线程。

package threaddeom;/** * user:ypc; * date:2021-06-12; * time: 9:35; */public class threaddemo10 { public static void main(string[] args) { thread thread1 = new thread(()->{ thread thread2 = new thread(() -> { },"thread2"); system.out.println("thread2是守护线程吗?:" thread2.isdaemon()); },"thread1"); system.out.println("thread1是守护线程吗?:" thread1.isdaemon()); //thread1.setdaemon(true); thread1.start(); // system.out.println("thread1是守护线程吗?:" thread1.isdaemon()); }}

彻底搞懂java多线程(一)

再看👇

package threaddeom;/** * user:ypc; * date:2021-06-12; * time: 9:35; */public class threaddemo10 { public static void main(string[] args) { thread thread1 = new thread(()->{ thread thread2 = new thread(() -> { },"thread2"); system.out.println("thread2是守护线程吗?:" thread2.isdaemon()); },"thread1"); system.out.println("thread1是守护线程吗?:" thread1.isdaemon()); thread1.setdaemon(true); thread1.start(); system.out.println("thread1是守护线程吗?:" thread1.isdaemon()); }}

彻底搞懂java多线程(一)

线程组

为了便于对某些具有相同功能的线程进行管理,可以把这些线程归属到同一个线程组中,线程组中既可以有线程对象,也可以有线程组,组中也可以有线程。使用线程模拟赛跑

public class threaddemo5 { //线程模拟赛跑(未使用线程分组) public static void main(string[] args) { thread t1 = new thread(new runnable() { @override public void run() { try { thread.sleep(1000); } catch (interruptedexception e) { e.printstacktrace(); } system.out.println(thread.currentthread().getname() "到达了终点"); } }, "选手一"); thread t2 = new thread(new runnable() { @override public void run() { try { thread.sleep(1200); } catch (interruptedexception e) { e.printstacktrace(); } system.out.println(thread.currentthread().getname() "到达了终点"); } }, "选手二"); t1.start(); t2.start(); system.out.println("所有选手到达了终点"); }}

运行结果:

彻底搞懂java多线程(一)

不符合预期效果,就可以使用线程组来实现

package threaddeom;/** * user:ypc; * date:2021-06-11; * time: 18:24; */class threadgroup1 { //线程分组模拟赛跑 public static void main(string[] args) { threadgroup threadgroup = new threadgroup("group"); thread t1 = new thread(threadgroup, new runnable() { @override public void run() { try { thread.sleep(1000); } catch (interruptedexception e) { e.printstacktrace(); } system.out.println("选手一到达了终点"); } }); thread t2 = new thread(threadgroup, new runnable() { @override public void run() { try { thread.sleep(1200); } catch (interruptedexception e) { e.printstacktrace(); } system.out.println("选手二到达了终点"); } }); t2.start(); t1.start(); while (threadgroup.activecount() != 0) { } system.out.println("所有选手到达了终点"); }}

彻底搞懂java多线程(一)

线程组常用的方法

彻底搞懂java多线程(一)

线程安全问题

来看单线程情况下让count分别自增和自减10000次

package threaddeom;/** * user:ypc; * date:2021-06-12; * time: 12:03; */class counter { private static int count = 0; public void increase(){ for (int i = 0; i < 10000; i ) { count ; } } public void decrease(){ for (int i = 0; i < 10000; i ) { count--; } } public int getcount(){ return count; }}public class threaddemo16 { public static void main(string[] args) { //单线程 counter counter = new counter(); counter.increase(); counter.decrease(); system.out.println(counter.getcount()); }}

结果符合预期

彻底搞懂java多线程(一)

如果想使程序的执行速度快,就可以使用多线程的方式来执行。在来看多线程情况下的问题

public class threaddemo16 { public static void main(string[] args) throws interruptedexception { //多线程情况下 counter counter = new counter(); thread thread1 = new thread(()->{ counter.decrease(); }); thread thread2 = new thread(()->{ counter.increase(); }); thread1.start(); thread2.start(); thread1.join(); thread2.join(); system.out.println(counter.getcount()); /* //单线程 counter counter = new counter(); counter.increase(); counter.decrease(); system.out.println(counter.getcount()); */ }}

执行结果:

彻底搞懂java多线程(一)

彻底搞懂java多线程(一)

彻底搞懂java多线程(一)

每次的执行结果是不一样的。这就是多线程的不安全问题

彻底搞懂java多线程(一)

预期的结果是0,但结果却不是。线程不安全问题的原因:

1.cpu的抢占式执行 2.多个线程共同操作一个变量 3.内存可见性 4.原子性问题 5.编译器优化(指令重排)

多个线程操作同一个变量

如果多个线程操作的不是一个变量,就不会发生线程的不安全问题,可以将上面的代码修改如下:👇

public class threaddemo16 { static int res1 = 0; static int res2 = 0; public static void main(string[] args) throws interruptedexception { counter counter = new counter(); thread thread1 = new thread(new runnable() { @override public void run() { res1 = counter.getcount(); } }); thread thread2 = new thread(new runnable() { @override public void run() { res2 = counter.getcount(); } }); system.out.println(res1 res2);/* //多线程情况下 counter counter = new counter(); thread thread1 = new thread(()->{ counter.decrease(); }); thread thread2 = new thread(()->{ counter.increase(); }); thread1.start(); thread2.start(); thread1.join(); thread2.join(); system.out.println(counter.getcount()); */ /* //单线程 counter counter = new counter(); counter.increase(); counter.decrease(); system.out.println(counter.getcount()); */ }}

这样就可以了:

彻底搞懂java多线程(一)

内存不可见问题:看下面的代码,是不是到thread2执行的时候,就会改变num的值,从而终止了thread1呢?

package threaddeom;import java.util.scanner;/** * user:ypc; * date:2021-06-12; * time: 13:03; */public class threaddemo17 { private static int num = 0; public static void main(string[] args) { thread thread1 = new thread(new runnable() { @override public void run() { while (num == 0){} } }); thread1.start(); thread thread2 = new thread(new runnable() { @override public void run() { scanner scanner = new scanner(system.in); system.out.println("输入一个数字来终止线程thread1"); num = scanner.nextint(); } }); thread2.start(); }}

结果是不能的:

彻底搞懂java多线程(一)

输入一个数字后回车,并没有让thread1的循环结束。这就是内存不可见的问题。

原子性的问题

上面的 和?操作其实是分三步来执行的

彻底搞懂java多线程(一)

假设在第二部的时候,有另外一个线程也来修改值,那么就会出现脏数据的问题了。

所以就会发生线程的不安全问题

编译器优化编译器的优化会打乱原本程序的执行顺序,就有可能导致线程的不安全问题发生。在单线程不会发生线程的不安全问题,在多线程就可能会不安全。

volatile关键字

可以使用volatile关键字,这个关键字可以解决指令重排和内存不可见的问题。

彻底搞懂java多线程(一)

加上volatile关键字之后的运行结果

彻底搞懂java多线程(一)

但是volatile关键字不能解决原子性的问题👇:

package threaddeom;/** * user:ypc; * date:2021-06-12; * time: 14:02; */class counter1 { private static volatile int count = 0; public void increase() { for (int i = 0; i < 10000; i ) { count ; } } public void decrease() { for (int i = 0; i < 10000; i ) { count--; } } public int getcount() { return count; }}public class threaddemo18 { public static void main(string[] args) throws interruptedexception { counter1 counter1 = new counter1(); thread thread1 = new thread(new runnable() { @override public void run() { counter1.decrease(); } }); thread thread2 = new thread(() -> { counter1.increase(); }); thread1.start(); thread2.start(); thread1.join(); thread2.join(); system.out.println(counter1.getcount()); }}

彻底搞懂java多线程(一)

彻底搞懂java多线程(一)

总结

本篇文章就到这里,希望可以帮到你,也希望您能够多多关注软科小院的其他文章!

网友评论
评论
更多编程技术
  • 编程技术推荐
更多
最新软件下载
网站地图