线程详解
来源:互联网 发布:虚拟机ubuntu无法联网 编辑:程序博客网 时间:2024/06/05 09:49
java多线程解决了什么问题?
并发通常可以解决“速度”和“设计可管理性问题”。
“并行”和“并发”的区别在于,“并行”是多个进程同时执行。而“并发”表面上看是多个线程同时执
行,而实际上是多个线程在轮换执行,也就是说某一时刻只有一个线程在运行。但是由于处理器的运行速度非常之快,所以给人的感觉是多个线程在同时运行。
说多线程解决“速度问题”有一个前提。
就是在多cpu的情况下。
当在单cpu时,多线程只能起到同时处理多个任务的作用,而并不会提高运行速度。
我们可以想象一种情境,就是如果我们需要同时给100个人打电话通知他们尽快回校参加培训。
如果在单线程的情况下,就等同于用同一台电话拨打100次通话。那么这时候如果该线路出现问题,后面的人都无法得到通知。
如果是多线程的情况下,如果某一个线路出现了阻塞,并不影响其他线路工作。
实现多线程的方式
- 通过实现Runnable接口
- 继承自Thread类
//通过实现Runnable public class RocketFacotry1 implements Runnable { //事实上任何线程的执行流程都是在Runnable接口的run()方法中执行 @Override public void run() { System.out.println(Thread.currentThread().getName() + "号生产线完成了一量火箭的组装!"); } public static void main(String[] args) { RocketFacotry1 facotry1 = new RocketFacotry1(); new Thread(facotry1).start(); new Thread(facotry1).start(); }}
运行结果
Thread-1号生产线完成了一量火箭的组装!
Thread-0号生产线完成了一量火箭的组装!
//通过继承Thread public class RocketFactory2 extends Thread { @Override public void run() { super.run(); System.out.println(Thread.currentThread().getName() + "号生产线完成了一量火箭的组装!"); } public static void main(String[] args) { new RocketFactory2().start(); new RocketFactory2().start(); }}
运行结果Thread-1号生产线完成了一量火箭的组装!
Thread-0号生产线完成了一量火箭的组装!
Thread内部也是通过执行Runnable接口的run()来运行线程
@Override public void run() { //此处的target是Runnable if (target != null) { target.run(); } }
Daemon线程
Daemon线程即守护线程,后台线程的特点是优先级比较低。当jvm中的非守护线程都运行结束的时候,那么Daemon守护线程也跟着结束。所以在使用守护线程的时候要慎重些
jvm的垃圾回收线程就是典型的(Daemon)守护线程。当jvm中没有其他的线程在运行时,垃圾回收线程也就跟着结束了
setDaemon一定要在线程的start之前设置,否则抛出IllegalThreadStateException异常
public static void main(String[] args) { Thread thread = new Thread(() -> { int num = 0; while (true) { try { Thread.sleep(20); System.out.println(Thread.currentThread().getName() + " is running!timestamp is " + System.currentTimeMillis() + " ,Daemon线程运行了" + num++ + "次"); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.setDaemon(true); thread.start(); try { Thread.sleep(500); Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("JVM运行结束,timestamp is " + System.currentTimeMillis()))); } catch (InterruptedException e) { e.printStackTrace(); }}
Thread-0 is running!timestamp is 1489134646030 ,Daemon线程运行了0次
Thread-0 is running!timestamp is 1489134646050 ,Daemon线程运行了1次
Thread-0 is running!timestamp is 1489134646070 ,Daemon线程运行了2次
Thread-0 is running!timestamp is 1489134646090 ,Daemon线程运行了3次
Thread-0 is running!timestamp is 1489134646117 ,Daemon线程运行了4次
Thread-0 is running!timestamp is 1489134646137 ,Daemon线程运行了5次
Thread-0 is running!timestamp is 1489134646157 ,Daemon线程运行了6次
Thread-0 is running!timestamp is 1489134646177 ,Daemon线程运行了7次
Thread-0 is running!timestamp is 1489134646197 ,Daemon线程运行了8次
Thread-0 is running!timestamp is 1489134646217 ,Daemon线程运行了9次
Thread-0 is running!timestamp is 1489134646237 ,Daemon线程运行了10次
Thread-0 is running!timestamp is 1489134646257 ,Daemon线程运行了11次
Thread-0 is running!timestamp is 1489134646277 ,Daemon线程运行了12次
Thread-0 is running!timestamp is 1489134646297 ,Daemon线程运行了13次
Thread-0 is running!timestamp is 1489134646317 ,Daemon线程运行了14次
Thread-0 is running!timestamp is 1489134646337 ,Daemon线程运行了15次
Thread-0 is running!timestamp is 1489134646357 ,Daemon线程运行了16次
Thread-0 is running!timestamp is 1489134646377 ,Daemon线程运行了17次
Thread-0 is running!timestamp is 1489134646397 ,Daemon线程运行了18次
Thread-0 is running!timestamp is 1489134646417 ,Daemon线程运行了19次
Thread-0 is running!timestamp is 1489134646437 ,Daemon线程运行了20次
Thread-0 is running!timestamp is 1489134646457 ,Daemon线程运行了21次
Thread-0 is running!timestamp is 1489134646477 ,Daemon线程运行了22次
Thread-0 is running!timestamp is 1489134646497 ,Daemon线程运行了23次
JVM运行结束,timestamp is 1489134646511Process finished with exit code 0
无论运行多少次,daemon线程中的时间戳永远小于主线程的,由此可见,当jvm中没有user线程在运行时,daemon线程也就跟着关闭了
Thread基本状态
在调用Thread实例start()方法后,基本状态为可执行状态(Runnable)、被阻塞状态(Blocked)、执行中(Running)几种状态
实例化Thread并执行start方法后,线程进入Runnable状态,此时线程尚未真正开始执行run()方法,必须等待排班器(Scheduler)插入cpu执行,线程才会执行run方法。
调用Thread.sleep()、进入synchronized前竞争对象锁定的阻断、调用wait()方法的阻断等、等待输入输出完成夜壶进入Blocked状态
安插线程
System.out.println("主线程开始运行"); Thread threadB = new Thread(() -> { System.out.println("Thread B开始执行..."); for (int i = 0; i < 5; i++) { System.out.println("Thread B执行中..."); } System.out.println("Thread B将结束..."); }); threadB.start(); threadB.join(); System.out.println("主线程将结束....");
一些Deprecated的api
1. stop方法被遗弃
1.即刻停止run()方法中剩余的全部工作,包括在catch或finally语句中,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。
2.会立即释放该线程所持有的所有的锁,导致数据得不到同步的处理,出现数据不一致的问题。
public class Main{ public static void main(String [] args) throws Exception{ TestObject testObject = new TestObject(); Thread t1 = new Thread(){ public void run(){ try { testObject.print("1", "2"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; t1.start(); Thread.sleep(1000); t1.stop(); System.out.println("first : " + testObject.getFirst() + " " + "second : " + testObject.getSecond()); }}class TestObject{ private String first = "ja"; private String second = "va"; public synchronized void print(String first, String second) throws Exception{ this.first = first; Thread.sleep(10000); this.second = second; } public String getFirst() { return first; } public void setFirst(String first) { this.first = first; } public String getSecond() { return second; } public void setSecond(String second) { this.second = second; }}
输出first : 1 second : va
2. resume和suspend方法被遗弃
suspend()和resume()必须要成对出现,否则非常容易发生死锁。
因为suspend方法并不会释放锁,如果使用suspend的目标线程对一个重要的系统资源持有锁,那么没任何线程可以使用这个资源直到要suspend的目标线程被resumed,如果一个线程在resume目标线程之前尝试持有这个重要的系统资源锁再去resume目标线程,这两条线程就相互死锁了,也就冻结线程。
public class Main{ public static void main(String [] args) throws Exception{ TestObject testObject = new TestObject(); Thread t1 = new Thread(){ public void run(){ testObject.print(); } }; t1.setName("A"); t1.start(); Thread.sleep(1000); Thread t2 = new Thread(){ public void run(){ System.out.println("B已启动,但进入不到print方法中"); testObject.print(); } }; t2.setName("B"); t2.start(); }}class TestObject{ public synchronized void print(){ if(Thread.currentThread().getName().equals("A")){ System.out.println("A 线程 独占该资源了"); Thread.currentThread().suspend(); } }}
3. destroy方法被遗弃
当线程处于suspend状态下,此时如果调用destroy方法销毁线程,并不会释放锁,那么其他线程将不再能获取到它锁定的资源.
停止线程
stop()方法不推荐使用了,那么我如果想要认为的让线程停止怎么办呢?
public class ThreadCustom implements Runnable { private boolean isContinue = true; @Override public void run() { while (isContinue) { System.out.println(Thread.currentThread().getName() + " is running!"); } } public void stop() { isContinue = false; } public static void main(String[] args) throws InterruptedException { ThreadCustom r = new ThreadCustom(); Thread thread = new Thread(r); thread.start(); Thread.sleep(500); r.stop(); }}
线程安全
- synchronized的使用
- 线程详解
- 线程详解
- *线程详解*
- 线程详解
- 线程详解
- 线程详解
- 线程详解
- 线程详解
- 线程详解
- 线程详解
- 线程详解
- 线程-线程详解
- 通用线程:POSIX 线程详解
- 通用线程:POSIX 线程详解
- 通用线程:POSIX 线程详解
- POSIX 线程详解
- Java线程详解
- POSIX 线程详解(1)
- iOS资源大全整理
- 静态导入、增强for循环
- C++ 关于“不允许使用数据成员初始值设定”的问题
- 复制构造函数
- struct class
- 线程详解
- 如何让孩子爱上设计模式 ——16.迭代器模式(Iterator Pattern)
- (3)FPQuant JHipster_使用AngularJS1
- 关于操作系统的几个重要概念(五)
- 坐标系的转换
- 图文并茂教你用iphone发短信控制自己的mac锁屏、关机等操作
- c++基础:如何string类型转换为int类型
- automaticallyAdjustsScrollViewInsets属性
- C 语言高效编程与代码优化