并发基础

并发基础线程 是程序执行流的最小单元 一个标准的线程由线程 ID 当前指令指针 PC 寄存器集合和堆栈组成 在 java 中可有两种方式实现多线程 一种是继承 Thread 类 一种是实现 Runnable 接口 Thread public class AdultVideoSh extends

大家好,我是讯享网,很高兴认识大家。
  • 线程,是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。
  • 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口。

Thread

public class AdultVideoShow1 extends Thread{ 
    private String name;//名称 public AdultVideoShow1(String name){ this.name=name; } public void run() { for(int i=0;i<5;i++){ System.out.println(name+" 使用了第"+(i+1)+"种姿势!"); try { sleep((int) Math.random() * 2); } catch (InterruptedException e) { e.printStackTrace(); } } } }

讯享网
讯享网public static void main(String[] args) { new AdultVideoShow1("泷泽萝拉").start(); new AdultVideoShow1("苍井空").start(); }

[print]

苍井空 使用了第1种姿势! 泷泽萝拉 使用了第1种姿势! 泷泽萝拉 使用了第2种姿势! 苍井空 使用了第2种姿势! 泷泽萝拉 使用了第3种姿势! 苍井空 使用了第3种姿势! 泷泽萝拉 使用了第4种姿势! 苍井空 使用了第4种姿势! 泷泽萝拉 使用了第5种姿势! 苍井空 使用了第5种姿势!

继承Thread类,并且实现run()方法,实现线程,start()是线程启动的方法;可以看出,两个线程是交替执行的!

Runnable

讯享网public class AdultVideoShow2 implements Runnable{ 
    private String name;//名称 public AdultVideoShow2(String name){ this.name=name; } @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<5;i++){ System.out.println(name+" 使用了第"+(i+1)+"种姿势!"); try { Thread.sleep((int) Math.random() * 2); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public static void main(String[] args) { new Thread(new AdultVideoShow2("小泽玛利亚")).start(); new Thread(new AdultVideoShow2("波多野结衣")).start(); }

[print]

讯享网小泽玛利亚 使用了第1种姿势! 波多野结衣 使用了第1种姿势! 波多野结衣 使用了第2种姿势! 小泽玛利亚 使用了第2种姿势! 波多野结衣 使用了第3种姿势! 小泽玛利亚 使用了第3种姿势! 波多野结衣 使用了第4种姿势! 小泽玛利亚 使用了第4种姿势! 波多野结衣 使用了第5种姿势! 小泽玛利亚 使用了第5种姿势!

实现Runnable接口,并且重写run()方法,实现线程,start()是线程启动的方法。

Runnable和Thread的区别

先看个例子

public class AdultVideoShow2 implements Runnable,AdultVideo{ 
    private int count=1; public AdultVideoShow2(){} @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+" 使用了第"+(count++)+"种姿势!"); try { Thread.sleep((int) Math.random() * 2); } catch (InterruptedException e) { e.printStackTrace(); } } } @Override public void warning() { // TODO Auto-generated method stub System.out.println(" FBI WARNING! "); System.out.println("Federal Law provides severe civil and criminal penalties for"); System.out.println("the unauthorized reproduction,distribution,or exhibition of "); System.out.println("copyrighted motion pictures!"); System.out.println(); } }
讯享网//另外一个接口 public interface AdultVideo { public void warning(); }
public static void main(String[] args) { AdultVideoShow2 av=new AdultVideoShow2(); av.warning(); new Thread(av,"小泽玛利亚").start(); new Thread(av,"波多野结衣").start(); }

[print]

讯享网 FBI WARNING! Federal Law provides severe civil and criminal penalties for the unauthorized reproduction,distribution,or exhibition of copyrighted motion pictures. 小泽玛利亚 使用了第1种姿势! 波多野结衣 使用了第2种姿势! 小泽玛利亚 使用了第3种姿势! 波多野结衣 使用了第4种姿势! 小泽玛利亚 使用了第5种姿势! 波多野结衣 使用了第6种姿势! 小泽玛利亚 使用了第7种姿势! 波多野结衣 使用了第8种姿势! 小泽玛利亚 使用了第9种姿势! 波多野结衣 使用了第10种姿势!
  1. 一部XX影片,开头都有警告之类的信息,那么我们新建一个接口,抽象打印警告信息的方法。这种需要实现多个接口的情况,只能选择Runnable接口的实现方式,才能避免继承的局限;
  2. 这次我们的XX影片更新了规则,两位明星每人要完成5个动作,并且不能重复,我们记录正常电影的动作总数。这种涉及到线程间的资源共享的情况,也只能选择Runnable接口的实现方式。

所以,在程序开发中只要是多线程肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:


讯享网

  • 避免点继承的局限,一个类可以继承多个接口。
  • 适合于资源的共享
  • 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

争用条件

总所众知,这几位明星实例非凡,我们将每位明星动作的总数加大,规则不变,记录所用明星完成的总动作数。

public class AdultVideoShow2 implements Runnable,AdultVideo{ 
    private int count=1; private int perCount=1; public AdultVideoShow2(){} public AdultVideoShow2(int perCount){ this.perCount=perCount; } @Override public void run() { for(int i=0;i<perCount;i++){ System.out.println(Thread.currentThread().getName()+" 使用了第"+(count++)+"种姿势!"); } @Override public void warning() { System.out.println(" FBI WARNING! "); System.out.println("Federal Law provides severe civil and criminal penalties for"); System.out.println("the unauthorized reproduction,distribution,or exhibition of "); System.out.println("copyrighted motion pictures!"); System.out.println(); } }
讯享网public static void main(String[] args) { AdultVideoShow2 av=new AdultVideoShow2(); av.warning(); new Thread(av,"小泽玛利亚").start(); new Thread(av,"波多野结衣").start(); }

[print]

小泽玛利亚 使用了第种姿势! 小泽玛利亚 使用了第种姿势! 小泽玛利亚 使用了第种姿势! 小泽玛利亚 使用了第种姿势! 小泽玛利亚 使用了第种姿势! 小泽玛利亚 使用了第种姿势! 小泽玛利亚 使用了第种姿势! 小泽玛利亚 使用了第种姿势! 

2位明星,每人10万个动作… (请无视),正确的结果应该是20万,但是结果却少了3!
这里写图片描述
[分析]
假定这里是单核,当极端情况发生时,即两位同时完成了动作,并且要求记录下来。线程1从内存中读取了count值为5,并且增加1,还没来得及写回内存时,cpu的时间片段耗尽;此时线程2获取了cpu时间片段,又从内存中读取了count,值仍然为5,增加1。这个时候无论线程1、线程2以何种顺序写回内存 结果都将是6,而正确的应该是7。

[解决]

讯享网public class AdultVideoShow2 implements Runnable,AdultVideo{ 
    private int count=1;//总动作数 private int perCount=1;//每人动作数 private final Object lockObj = new Object();//锁 public AdultVideoShow2(){} public AdultVideoShow2(int perCount){ this.perCount=perCount; } @Override public void run() { synchronized(lockObj){ for(int i=0;i<perCount;i++){ System.out.println(Thread.currentThread().getName()+" 使用了第"+(count++)+"种姿势!"); } lockObj.notifyAll();// } } @Override public void warning() { System.out.println(" FBI WARNING! "); System.out.println("Federal Law provides severe civil and criminal penalties for"); System.out.println("the unauthorized reproduction,distribution,or exhibition of "); System.out.println("copyrighted motion pictures!"); System.out.println(); } }

[print]

波多野结衣 使用了第种姿势! 波多野结衣 使用了第种姿势! 波多野结衣 使用了第种姿势! 波多野结衣 使用了第种姿势! 波多野结衣 使用了第种姿势! 

加入互斥与同步(synchronized/notifyAll),得到了正确的结果。

线程状态

这里写图片描述

  • 初始状态(New):新创建了一个线程对象。
  • 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
  • 运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
  • 阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
  • 死亡状态(dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
小讯
上一篇 2025-03-20 09:06
下一篇 2025-03-11 10:37

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/58520.html