精华内容
下载资源
问答
  • 父类和子类中分别有一个同步方法(没有重写),然后开启两个线程分别执行其中一个同步方法,最终结果是串行。结论:父类和子类中的同步方法是同一个锁。测试代码如下: SynParent.java public class ...

    结论:

    父类和子类中分别有一个同步方法(没有重写),然后开启两个线程分别执行其中一个同步方法,最终结果是串行。结论:父类和子类中的同步方法是同一个锁。测试代码如下:


    SynParent.java


    public class SynParent {


        public synchronized void synParent(){
            try {
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.printf("父类同步方法输出---------->结束时间:"+System.currentTimeMillis()+"\n");
        }


    }




    SynChild.java


    public class SynChild extends SynParent{


        public synchronized void synChild(){
            try {
                Thread.sleep(2000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.printf("子类同步方法输出---------->结束时间:"+System.currentTimeMillis()+"\n");
        }


    }


    SynParentAndChildTest.java


    public class SynParentAndChildTest extends Thread{
        SynChild synChild;
        int index;
        public SynParentAndChildTest(SynChild synChild,int index) {
            this.synChild = synChild;
            this.index = index;
        }
        @Override
        public void run() {
            super.run();
            if (0 == index){
                System.out.printf("开始执行父类方法------>时间:"+System.currentTimeMillis()+"\n");
                synChild.synParent();
            }else {
                System.out.printf("开始执行子类方法------>时间:"+System.currentTimeMillis()+"\n");
                synChild.synChild();
            }
        }
    }


    main:


    private static void synParentAndChildTest(){
            SynChild synChild = new SynChild();
            for (int i = 0; i < 2; i++){
                SynParentAndChildTest synParentAndChildTest = new SynParentAndChildTest(synChild,i);
                synParentAndChildTest.start();
            }

      }


    结果:



    展开全文
  • 父类中添加虚函数,父类中调用这个虚函数,子类继承父类后,子类实现的虚函数就会

    在父类中添加虚函数,父类中调用这个虚函数,子类继承父类后,子类实现的虚函数就会在父类调用的时候自动响应;


    一:例子:

    如:计算机上链接多个摄像头,设计一个类,每一个对象可以关联一个摄像头,当图像获取的时候将图像通过虚函数传递给子类;

    class A
    {
    public:


    virtual void BufferCB( BYTE * pBuf, int nLen ) = 0; //设计为纯虚函数,这样必须继承实现;
    //virtual void BufferCB( BYTE * pBuf, int nLen ){};




    public:
    static UINT thread_t(PVOID pParam )
    {
    A * pA = (A*)pParam;

                   int i = 0;

    while(1)
    {

    char buf[100] = {0};
           sprintf( buf, "BufferCB pBuf is: %d", i++); 
     
    pA->BufferCB( (BYTE*)buf, strlen(buf)+1 );


    Sleep(1000);
    }


    return 0;
    }


    void start()
    {
    AfxBeginThread( thread_t, this );
    }
     


    };



    class New_A : public A
    {
    public:
    void BufferCB( BYTE * pBuf, int nLen )
    {
    //AfxMessageBox( CString( (char*)pBuf ) );


    OutputDebugStr( CString(( char* )pBuf) );
    }
    };


    //应用:

    //说明:从这个例子可以看出 每一New_A的对象都对应着一个自己的线程,每个线程处理自己相关的类中的内容(  int i = 0;);

    void tA()
    {
     New_A  * New_A_obj_1 = new New_A;
     New_A  * New_A_obj_2 = new New_A;


      New_A_obj_1->start();
      New_A_obj_2->start();
    }






    二:例子:

    另一个模式: 

    如:计算机上只有一个摄像头, 但是 有多个模块(类)中都需要这个摄像头的图像;

            或者如:计算机时间, 当时间变化时, 所有和时间显示获取相关的模块都要获取到时间的变化;


    解决这个问题一般有两个模式,

    1:拉模式: 就是启动一个线程,实时监控对象状态(摄像头,时间),如果有变化,就获取相关的数据;

    2:推模式:相关对象,对摄像头,或时间模块进行“消息注册”,如果有变化,就通知(调用)相关对象的函数;


    一般情况,拉模式比较浪费系统资源,而且效率较低,建议用推模式;


    class B
    {
    public:


    virtual void BufferCB( BYTE * pBuf, int nLen ) = 0;
    //virtual void BufferCB( BYTE * pBuf, int nLen ){};



    public:
    B()
    {
    m_vector_B.push_back( this );


    if ( m_vector_B.size() == 1 )
    {
    AfxBeginThread( thread_t_All, 0 );
    }
    }


    static std::vector<B *> m_vector_B;
    //
    static UINT thread_t_All(PVOID pParam )
    {




    while(1)
    {
    if ( m_vector_B.size() > 0 )
    {
    static int i = 0;
    char buf[100] = {0};
    sprintf( buf, "BufferCB pBuf is: %d", i++); 


    for ( int n = 0; n<m_vector_B.size(); n++)
    {
    B * pB = m_vector_B.at(n);


    pB->BufferCB( (BYTE*)buf, strlen(buf)+1 );
    }









    Sleep(1000);
    }


    return 0;
    }


    void start_all()
    {
    AfxBeginThread( thread_t_All, 0 );
    }


    };


    vector<B*> B::m_vector_B;




    class New_B : public B
    {
    public:
    void BufferCB( BYTE * pBuf, int nLen )
    {
    //AfxMessageBox( CString( (char*)pBuf ) );


    OutputDebugStr( CString(( char* )pBuf) );
    }
    };


    //应用:

    //说明:线程的启动,和指针的获取在__super类的构造函数中获取,关于指针和继承的内存模型就不多说了;

    //这样每一创建的对象在数据变化的时候都可以获取同样的数据了;

    //如时间变化了,__super类就循环的通知了所有注册的(在m_vector_B中的)对象模块了;

    void tB()
    {
    New_B * New_B_obj_1  = new  New_B;
    New_B * New_B_obj_2  = new  New_B;;
    }


    //

    关于上述另个方法,都是父类通过虚函数调用子类实现的虚函数;

    不同的是,方法一,会启动多个线程,每个对象维护一个自己相关的线程,获取的都是自己模块的数据;每个模块数据一般不同;如:例子中,每个对象获取不同摄像的图像;

    方法二:只启动一个线程,所有的对象模块获取的都是相同的数据;如:所有对象获取的都是同一摄像的相同图像;


    这类模式方法在 MFC的CWnd消息,Qt的QWidget的event 都是同样的方法;

    展开全文
  • ②final 修饰方法:此方法不能重写,即父类中某方法被final修饰,在子类中将不能定义一个与父类final 方法同名且有相同方法标识符(参数个数也相同,返回值类型相同)的方法 ③final 修饰类:此类不能再派生子类 ④...

    1,final 修饰符修饰变量、方法、类 时有什么作用?

    ①final 修饰变量:该变量被赋初值后,不能对它重新赋值

    ②final 修饰方法:此方法不能重写,即父类中某方法被final修饰,在子类中将不能定义一个与父类final 方法同名且有相同方法标识符(参数个数也相同,返回值类型相同)的方法

    ③final 修饰类:此类不能再派生子类

    ④final 修饰的实例变量在使用前必须显示地初始化。对于普通实例变量,可以默认初始化:如引用类型的实例变量,默认初始化值为null,但使用final修饰实例变量后,该变量可使用以下三种方式显示初始化: a)在定义final实例变量时指定初始值 b)在非静态初始化块中指定初始值 c)在构造器中初始化

    ⑤局部变量被final修饰时,a)局部变量的值不能再被改变 b)局部变量在使用前必须显示初始化(其实JAVA本来就要求局部变量在使用之前要先初始化)

    ❻当使用final修饰变量时(包括局部变量、实例变量、类变量),如果在定义该final变量时就指定了初始值,则该变量的值在编译阶段就已经被确定下来了,此时该变量类似于C中的宏变量。认识到这一点很重要!!!这样就能理解为什么有些变量值的初始化在奇怪,原来它们是在编译期就已经确定了。这也是为什么在《JAVA并发编程实践》一书中 为了保证线程的安全性,应尽量将变量定义成final的一个原因。另一个原因,我想应该是:带有final修饰的变量具有“不变性”,而不变性正是线程安全的一个特征。

    ⑦为什么要求内部类中访问的局部变量(在方法体中定义的变量)必须使用final修饰?

    内部类访问局部变量,显然该内部类是一个局部内部类(在方法中定义的类)那为什么局部变量要用final修饰呢?答案是final修饰的局部变量不可变。对于局部变量而言,它的生命周期局限于方法体内,当方法结束时,局部变量的作用域也随之结束。但当在内部类中访问局部变量时,内部类会扩大局部变量作用域的生命周期,这时,保证该局部变量的不可变性对于程序的安全是很重要的。看下面示例:

    public class Test {
    	public static void main(String[] args) {
    		final String str = "Hello";
    		
    		new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				for(int i = 0; i < 100; i++){
    					System.out.println(str);
    					try{
    						Thread.sleep(100);
    					}catch(InterruptedException e){}
    				}
    			}
    		}).start();
    	}
    }

    局部变量str 在main方法中定义,当main方法执行到 .start() 时,main方法的主线程结束了,但是new Thread创建的线程还未结束,它继续在访问str变量的值。


    2,super 关键字如何理解?

    ①借助super关键字,可以在子类中调用父类的变量或方法(假设访问权限允许)。但需要注意的是:super不是一个变量,不能像this那样,当做变量来用。如,return this; 是允许的,但是 return super; 则不行。super神奇的地方在于,super并不是一个父类对象的引用(变量),但是可以通过super.method()、super.field  来访问调用父类中的方法以及访问父类中的变量。


    3,子类继承了父类时,子类中的实例变量与父类中的实例变量有哪些关系?

    ①在继承中,当new 一个子类对象时,首先会去执行父类的构造器,初始化父类的实例变量。即相当于new 子类对象时,隐含生成了一个父类对象,但是貌似是无法直接操纵这个父类对象的,能对父类做一些操作都是通过super关键字来完成的,如super.method(),super.field。

    那么,当子类中有与父类同名的实例变量时,子类的实例变量会隐藏父类的实例变量,若要访问父类的实例变量就是前面提到的使用super关键字。

    ②通过引用来调用方法和通过引用来访问变量,JAVA处理是不同的。如,假设有一个引用变量obj,obj.method() 调用的是obj实际指向的引用类型的方法,而obj.field 访问的是声明obj类型的属性。看下面示例:

    class Base{
    	int count = 2;
    	void method(){
    		System.out.println("Base Method");
    	}
    }
    
    public class Sub extends Base{
    	int count = 20;
    	
    	@Override
    	void method(){
    		System.out.println("Sub Method");
    	}
    	public static void main(String[] args) {
    		Sub s = new Sub();
    		Base b = s;
    		System.out.println(s.count);//20
    		System.out.println(b.count);//2
    		s.method();//Sub Method
    		b.method();//Sub Method
    	}
    }
    b.count 为2,因为b声明成Base类型。b.method()输出: Sub Method,因为b实际指向的还是子类型Sub。

    看一段解释:当变量的编译时类型和运行时类型不同时,通过该变量访问它引用的对象的实例变量时,该实例变量的值由声明该变量的类型决定。但是通过该变量调用它引用的对象的实例方法时,该方法行为将由它实际所引用的对象来决定。

    ③不要在父类的构造器中调用被子类重写的方法(说得更直白一点:不要在父类的构造器中调用子类的方法),因为当 new 子类对象时,会先执行父类构造器中的方法,在父类构造器中调用子类的方法,而此时子类的对象都还没有初始化完成!这也是为什么在JAVA多线程中所不允许的。这会造成很大的线程不安全性。比如,子类中重载的某方法会修改子类的实例变量,若在父类的构造器调用了该重载方法修改了子类的实例变量,而此时子类变量尚未初始化,将会造成子类实例变量的极大不确定性。



    展开全文
  • 子类父类成员变量线程安全问题

    千次阅读 2019-12-03 13:54:19
    Java父类子类的 内存引用讲解 从对象的内存角度来理解试试. 假设现在有一个父类Father,它里面的变量需要占用1M内存.有一个它的子类Son,它里面的变量需要占用0.5M内存. 现在通过代码来看看内存的分配情况: ...

    Java父类与子类的 内存引用讲解

    从对象的内存角度来理解试试.
    假设现在有一个父类Father,它里面的变量需要占用1M内存.有一个它的子类Son,它里面的变量需要占用0.5M内存.
    现在通过代码来看看内存的分配情况:
    Father f = new Father();//系统将分配1M内存.

    Son s = new Son();//系统将分配1.5M内存!因为子类中有一个隐藏的引用super会指向父类实例,所以在实例化子类之前会先实例化一个父类,也就是说会先执行父类的构造函数.由于s中包含了父类的实例,所以s可以调用父类的方法.

    Son s1 = s;//s1指向那1.5M的内存.

    Father f1 = (Father)s;//这时f1会指向那1.5M内存中的1M内存,即是说,f1只是指向了s中实例的父类实例对象,所以f1只能调用父类的方法(存储在1M内存中),而不能调用子类的方法(存储在0.5M内存中).

    Son s2 = (Son)f;//这句代码运行时会报ClassCastException.因为f中只有1M内存,而子类的引用都必须要有1.5M的内存,所以无法转换.

    Son s3 = (Son)f1;//这句可以通过运行,这时s3指向那1.5M的内存.由于f1是由s转换过来的,所以它是有1.5M的内存的,只是它指向的只有1M内存.

    前提是:每个子类都实例化对象,即多例情况(非单例)

    每一个子类都实例化了,其父类也会随之使例化,接着子类再实例化,父类、子类里面的属性字段都是独立的,所以处于公用部分的其父类中的成员变量 就相当于是线程安全的

    package abstracts;
    
    public abstract class B {
        /**
         * 子类实例化后,父类也被实例化,所以在子类多例的情况下,父类中的成员变量:
         * private String str 是线程安全的
         */
        private String str;
    
        public B() {
            System.out.println("父类已经实例化");
        }
    
        public B(String a) {
            this.str = a;
            System.out.println(str);
        }
    
        public abstract void play();
    }  
    package abstracts;
    
    public class C extends B {
    
        public C(String c) {
            super(c);
            System.out.println("子类已经被实例化");
        }
    
        @Override
        public void play() {
            System.out.println("我实现了父类的方法");
        }
    
        public static void main(String[] args) {
            B c = new C("c");
            B c1 = new C("b");
        }
    
    
    }  

    打印结果:

    c
    子类已经被实例化
    b
    子类已经被实例化
    

     

    展开全文
  • 继承Thread实现多线程
  • List子类和父类的区别作用

    千次阅读 2019-05-19 22:57:19
    标题List与父类的介绍List与子类的介绍 List与父类的介绍 当数据的时候,则采用对象的方式来设置值;但当对象的时候,则采用集合也就是List或他的“兄弟”set来存对象;而获取数据,则需要用到他俩的父类...
  • 1、 重写父类 1) 子类定义父类同名函数后,父类函数被覆盖; 2) 如果需要,可以在子类...方法()”的重点是不需要提供父类,这意味着如果改变了类继承关系,只需要修改类定义的那行中的父类名称即可。此时寻找父...
  • 创建多线程的第一种方式——创建Thread子类和重写run方法; 第二种方式——实现Runnable接口,实现类传参给父类Thread类构造方法创建线程; 第一种方式创建Thread子类和重写run方法: 创建线程: 主线程调用...
  • 昨天写了一段代码,其中就出现了用子类创建父类对象,却调用不了子类方法的问题`import java.awt.BorderLayout; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; ...
  • 今天在学习线程时,按照教程新建一个子类,定义该子类继承第三方库的一个Thread类,但是在写代码 指明继承时,父类死活没有提示,找了百度n种方法都未解决,后来突然发现把上面的代码 注释掉,就又给提示了,不知道...
  • 第一种方法:摘要Qt多线程方法1 继承QThread1写一个继承于QThread的线程2 QThread的几个函数quitexitterminate函数3 正确的终止一个线程4 如何正确启动一个线程41正确的启动一个全局线程UI一直存在的线程42 如何...
  • Chromium多线程模型设计实现分析

    万次阅读 多人点赞 2015-07-27 00:59:08
    Chromium除了远近闻名的多进程架构之外,它的多线程模型也相当引人注目的。Chromium的多进程架构是为了解决网页的稳定性问题,而多线程模型则是为了解决网页的卡顿问题...本文就分析Chromium的多线程模型的设计实现。
  • 在编写Thread类的子类时,需要重写父类的run()方法,其目的是规定线程的具体操作,否则线程就没有开始的地方 在这里,做一个小小总结:  ··在线程的编写的时候,要重写父类的run()方法,在run()...
  • 首先,父类有一个抽象方法,并且在自身的其他方法中调用了 public abstract class Baba { public abstract void say(String a); public void dosomething(String a){ say(a); } } 父类 baba,有一个say抽象方法,...
  • 多线程

    2019-10-14 18:42:06
    世间万物都可以同时完成很多工作 这种思想在java中被称为并发,而将并发完成的每一件事情称为 多线程 2…多线程的概述 每一个线程完成一个功能,并与其他线程并发执行,这种机制被称为多线程 3…实现多线程的两种...
  • Java多线程 - 线程创建启动

    千次阅读 2018-06-06 23:26:27
    Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。线程的创建一般有以下三种:一、继承Thread类创建线程类定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了...
  • } } } 如果不是同一个锁,super锁住了父类对象,那么另一个线程仍然可以获得子类对象的锁。按照这个假设,以下程序应该输出 something sleepy! something else woke up! 但输出的是 something sleepy! woke up...
  • 在Java中,子类实例化时会调用父类构造方法,子类父类方法中会有一个函数生成表,执行时实现动态链接,子类重写父类方法时执行顺序也是这样  对于执行父类构造方法的问题。可以归纳为两种情况 1,如果...
  • 【java多线程编程】三种多线程的实现方式

    万次阅读 多人点赞 2019-01-01 16:20:56
    基于Runnable接口实现多线程Thread 与 Runnable 的关系Callable实现多线程线程运行状态 前言 &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在java语言最大的特点是支持...
  • 我们都知道多线程有两种创建方式: 1、通过thread子类创建,子类重写了父类中的run方法;重写run方法是为了写线程的执行内容;不重写的话调用父类的run方法,父类run方法是 public void run(){ if(this....
  • java多线程

    2013-02-07 17:00:08
    java内置了多线程机制,所以java可以创建多线程的程序。java创建多线程有两种方式: 方式一:继承Thread类 子类覆盖父类中的run方法,将线程运行的代码存放在run中。 建立子类对象的同时线程也被创建。 通过调用...
  • Python多线程之线程创建终止

    万次阅读 2014-10-21 12:33:45
    python主要是通过threadthreading这两个模块来实现多线程支持。python的thread模块是比较底层的模块,python的threading模块是对thread做了一些封装,可以更加方便的被使用。Python threading模块不同于其他语言之...
  • 前面两篇介绍了两种多线程的实现...这篇,我们先来看看第二种方式的实现原理,然后分析对比两种多线程实现的区别优缺点。 1.实现runnable的原理 看下面代码,然后ctrl+点击鼠标查看Thread的有参构造,跟着ta...
  • * 多线程基本使用实例 * 1.第一种实现方法:继承Thread父类子类中重写run()方法,方法体中放入任务代码, * 然后new出子类对象,使用start()方法开启子线程,但这种开启方式的弊端是子类如 * 果继承了Thread类...
  • JAVA之旅(十二)——Thread,runstart的特点,线程运行状态,获取线程对象名称,多线程实例演示,使用Runnable接口 开始挑战一些难度了,线程I/O方面的操作了,继续坚持 一.Thread 如何在自定义的代码中,...
  • Python异常处理和多线程

    千次阅读 2017-06-30 09:38:46
    由于每个进程只要干一件事,所以,一个进程只要有一个线程,当然,想 Word这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多线程是一样的,也是由操作系统在多个线程之间快速切换,让每个...
  • Python实战之多线程编程threading.Thread

    万次阅读 2011-02-16 08:38:00
    在Python中可以使用继承threading.Thread类来实现多线程编程,其中子类可以重写父类的__init__run方法来实现用户线程的逻辑,如下是一个简单的多线程类实现 import threading class MyThread...
  • 程序的其余部分根本察觉不到有什么变化(假设程序不需要多线程的同步 的话)。  只要一个被引用的对象存在抽象类型,就应当任何引用此对象的地方使 用抽象类型,包括参量的类型声明、方法返回类型的声明、属性变量...
  • Java父类强制转换子类原则

    千次阅读 2018-01-25 09:35:56
    最近,微信群友在讨论子类父类的转换问题,其实不难,给大家用实例来说明一下就很明了了。 我们知道Java中子类转换成父类是没有任何问题的,那父类可以转换成子类吗? 来看下面这段程序: public class ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 108,835
精华内容 43,534
关键字:

多线程父类和子类的关系