本篇文章给人人带来的内容是关于java多线程的基础知识总结(附代码),有肯定的参考价值,有须要的朋侪能够参考一下,愿望对你有所协助。
Java 主线程名
我们启动的一个递次能够明白为一个历程, 一个历程中包含一个主线程, 线程能够明白为一个子使命. Java 中能够经由过程下面代码来猎取默许的主线程名.
System.out.println(Thread.currentThread().getName());
运转效果为 main, 这是线程的名字并非 main 要领, 经由过程此线程来实行 main 要领罢了.
两种体式格局建立线程
1.继承 Thread 类
public class Thread1 extends Thread { @Override public void run() { System.out.println("qwe"); } }
2.完成 Runnable 接口
public class Thread2 implements Runnable { @Override public void run() { System.out.println("asd"); } }
Thread 完成 Runnable 接口. 而且多线程运转时, 代码的实行递次与挪用递次是无关的. 别的假如屡次挪用 start要领则会抛出 java.lang.IllegalThreadStateException
currentThread 要领
返回当前代码正在被哪一个线程挪用.
public class Thread1 extends Thread { public Thread1() { System.out.println("组织要领的打印:" + Thread.currentThread().getName()); } @Override public void run() { System.out.println("run 要领的打印:" + Thread.currentThread().getName()); } }
Thread1 thread1 = new Thread1(); thread1.start();
isAlive 要领
推断当前线程是不是处于运动状况.
public class Thread1 extends Thread { @Override public void run() { System.out.println("run 要领的打印 Thread.currentThread().isAlive() == " + Thread.currentThread().isAlive()); System.out.println("run 要领的打印 this.isAlive() == " + this.isAlive()); System.out.println("run 要领的打印 Thread.currentThread().isAlive() == this.isAlive() == " + (Thread.currentThread() == this ? "true" : "false")); } }
Thread1 thread1 = new Thread1(); System.out.println("begin == " + thread1.isAlive()); thread1.start(); Thread.sleep(1000); System.out.println("end == " + thread1.isAlive());
实行效果以下
begin == false run 要领的打印 Thread.currentThread().isAlive() == true run 要领的打印 this.isAlive() == true run 要领的打印 Thread.currentThread() == this == true end == false
thread1 在 1秒以后实行完成. 所以输出效果为 false. 而且 Thread.currentThread() 和 this 是同一个对象, 能够明白成实行当前 run 要领的线程对象就是我们本身(this).
假如将线程对象以组织参数的体式格局传递给 Thread 对象举行 start() 启动时, 运转效果和前面实例是有差别的. 形成如许的差别的缘由照样来自于 Thread.currentThread() 和 this 的差别.
System.out.println("begin == " + thread1.isAlive()); //thread1.start(); // 假如将线程对象以组织参数的体式格局传递给 Thread 对象举行 start() 启动 Thread thread = new Thread(thread1); thread.start(); Thread.sleep(1000); System.out.println("end == " + thread1.isAlive());
实行效果
begin == false run 要领的打印 Thread.currentThread().isAlive() == true run 要领的打印 this.isAlive() == false run 要领的打印 Thread.currentThread() == this == false end == false
Thread.currentThread().isAlive() 是 true 的缘由是由于, Thread.currentThread() 返回的是 thread 对象, 而我们也是经由过程此对象来启动线程的, 所以是在运动状况.
this.isAlive() 是 false 就比较好明白了, 由于我们是经由过程 thread 对象启动的线程来实行 run 要领的. 所以它是 false. 同时也申明这两个不是同一个对象.
sleep 要领
在指定的毫秒数内让当前 "正在实行的线程" 休眠. "正在实行的线程" 只得是 Thread.currentThread()
返回的线程.
Thread.sleep(1000);
住手线程
住手一个线程意味着在线程处置惩罚完使命之前停掉正在做的操纵, 也就是摒弃当前的操纵.
在 Java 中有以下 3 种要领能够停止正在运转的线程:
运用退出标志, 使线程一般退出, 也就是当 run 要领完成后线程停止.
运用 stop 要领强行停止线程, 然则不引荐运用这个要领.
运用 interrupt 要领中断线程.
停不了的线程
挪用 interrupt 要领仅仅是当前线程打了一个住手标记, 并非真正的住手线程.
public class Thread1 extends Thread { @Override public void run() { for(int i = 0; i < 500000; i++) { System.out.println(i); } } }
Thread1 thread1 = new Thread1(); thread1.start(); Thread.sleep(2000); thread1.interrupt();
我们两秒后挪用 interrupt 要领, 依据打印效果我们能够看到线程并没有住手, 而是在实行完 500000 此轮回后 run 要领完毕线程住手.
推断线程是不是是住手状况
我们将线程标记为住手后, 须要在线程内部推断一下这个线程是不是是住手标记, 假如是则住手线程.
两种推断要领:
Thread.interrupted(); 也能够运用 this.interrupted();
this.isInterrupted();
下面是两个要领的源码:
public static boolean interrupted() { return currentThread().isInterrupted(true); } public boolean isInterrupted() { return isInterrupted(false); }
interrupted()
要领数据静态要领, 也就是推断当前线程是不是已中断. isInterrupted()
推断线程是不是已被中断.
来自官网的interrupted()
要领重点.
线程的 中断状况 由该要领消灭. 换句话说, 假如一连两次挪用该要领, 则第二次挪用将返回 false (在第一次挪用已消灭了其中断状况以后, 且第二次挪用磨练完中断状况前, 当前线程再次中断的状况除外).
非常住手线程
public class Thread1 extends Thread { @Override public void run() { try { for (int i = 0; i < 500000; i++) { if (this.isInterrupted()) { System.out.println("线程住手"); throw new InterruptedException(); } System.out.println("i = " + i); } } catch (InterruptedException e) { System.out.println("线程经由过程 catch 住手"); e.printStackTrace(); } } }
Thread1 thread1 = new Thread1(); thread1.start(); Thread.sleep(1000); thread1.interrupt();
输出效果, 这是末了几行:
i = 195173 i = 195174 i = 195175 线程住手 线程经由过程 catch 住手 java.lang.InterruptedException at Thread1.run(Thread1.java:9)
固然我们也能够将throw new InterruptedException();
换成return
. 都是一样能够完毕线程的.
在甜睡中住手
假如线程挪用 Thread.sleep()
要领使线程举行休眠, 这时刻我们挪用 thread1.interrupt()
后会抛出. InterruptedException
非常.
java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at Thread1.run(Thread1.java:8)
暴力住手线程
暴力住手线程能够运用 stop
要领, 但此要领已过期并不引荐运用, 缘由以下.
马上抛出 ThreadDeath 非常, 在线程的run()要领内, 任何一点都有能够抛出ThreadDeath Error, 包含在 catch 或 finally 语句中. 也就是说代码不确定实行到哪一步就会抛出非常.
开释该线程所持有的一切的锁. 这能够会致使数据不一致性.
public class Thread1 extends Thread { private String userName = "a"; private String pwd = "aa"; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } @Override public void run() { this.userName = "b"; try { Thread.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } this.pwd = "bb"; } }
Thread1 thread1 = new Thread1(); thread1.start(); Thread.sleep(1000); thread1.stop(); System.out.println(thread1.getUserName() + " " + thread1.getPwd());
输出效果为:
b aa
我们在代码中然线程休眠 Thread.sleep(100000); 是为了模仿一些别的营业逻辑处置惩罚所用的时刻, 在线程处置惩罚别的营业的时刻, 我们挪用 stop 要领来住手线程.
线程是被住手了也实行了 System.out.println(thread1.getUserName() + " " + thread1.getPwd()); 来帮我们输出效果, 然则 this.pwd = "bb"; 并没有被实行.
所以, 当挪用了 stop 要领后, 线程不管实行到哪段代码, 线程就会马上退出, 而且会抛出 ThreadDeath 非常, 而且会开释一切锁, 从而致使数据不一致的状况.
interrupt 比拟 stop 要领更可控, 而且能够坚持数据一致, 当你的代码逻辑实行完一次, 下一次实行的时刻, 才会去推断并退出线程.
假如人人不怎么明白引荐检察 为何不能运用Thread.stop()要领? 这篇文章. 下面是另一个比较好的例子.
假如线程当前正持有锁(此线程能够实行代码), stop以后则会开释该锁. 由于此毛病能够出现在许多处所, 那末这就让编程职员防不胜防, 极易形成对象状况的不一致. 比方, 对象 obj 中存放着一个局限值: 最小值low, 最大值high, 且low不得大于high, 这类关联由锁lock庇护, 以防止并发时发生竞态前提而致使该关联失效.
假定当前low值是5, high值是10, 当线程t猎取lock后, 将low值更新为了15, 此时被stop了, 真是蹩脚, 假如没有捕捉住stop致使的Error, low的值就为15, high照样10, 这致使它们之间的小于关联得不到保证, 也就是对象状况被破坏了!
假如在给low赋值的时刻catch住stop致使的Error则能够使背面high变量的赋值继承, 然则谁也不知道Error会在哪条语句抛出, 假如对象状况之间的关联更庞杂呢?这类体式格局几乎是没法保护的, 太庞杂了!假如是中断操纵, 它决计不会在实行low赋值的时刻抛出毛病, 如许递次关于对象状况一致性就是可控的.
suspend 与 resume 要领
用来停息和恢复线程.
独有
public class PrintObject { synchronized public void printString(){ System.out.println("begin"); if(Thread.currentThread().getName().equals("a")){ System.out.println("线程 a 被中断"); Thread.currentThread().suspend(); } if(Thread.currentThread().getName().equals("b")){ System.out.println("线程 b 运转"); } System.out.println("end"); } }
try{ PrintObject pb = new PrintObject(); Thread thread1 = new Thread(pb::printString); thread1.setName("a"); thread1.start(); thread1.sleep(1000); Thread thread2 = new Thread(pb::printString); thread2.setName("b"); thread2.start(); }catch(InterruptedException e){ }
输出效果:
begin 线程 a 被中断
当挪用 Thread.currentThread().suspend(); 要领来停息线程时, 锁并不会被开释, 所以形成了同步对象的独有.
以上就是java多线程的基础知识总结(附代码)的细致内容,更多请关注ki4网别的相干文章!