您的位置:首页 > 职场人生

黑马程序员————java基础---------多线程与反射

2014-11-24 22:05 302 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

第一部分多线程:

java语言是为数不多的支持多线程的语言。

进程:当程序进入内存运行时,即变成了一个进程。进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位。

硬盘和内存都可以存储数据。硬盘是持久存储设备,内存是临时存储设备,内存的数据,在断电之后就消失了,内存的速度快。

进程特征:

1、独立性:每一个进程都拥有自己私有的地址空间。

2、动态性:程序只是一个静态的指令集合,进程是一个正在系统中活动的指令集合。

3、并发性:多个进程可以在单个处理器上并发执行,多个进程之间不会互相影响。

线程是进程的执行单元,执行路径,使得同一个进程可以同时并发处理多个任务。

一个进程中至少有一个线程在负责该进程的运行。

对于一个CPU而言,它在某个时间点只能执行一条线程。CPU在不断地在进行这些线程之间轮换执行。这种切换速度是快速的,我们感受不到这种速度。

在多线程中,由于存在着CPU切换线程来执行的过程,因此就让多线程运行有了一个随机性。

JVM的多线程中,至少有两个,一个是负责自定义代码运行的。

一个是负责垃圾回收的。

案例:

class RubbishDemo{
public void finalize(){
System.out.println("垃圾回收器执行");
}
}

class Demo{
public static void main(String [] args){
new RubbishDemo();
new RubbishDemo();
new RubbishDemo();
System.gc();

}
}


注意:通过控制台输出,我们会发现,输出"垃圾回收期执行"这句话的次数不同,有的是一次,有的是两次,有的是三次等,这就说明,虽然我们调用了垃圾回收器,但是CPU在处理指令的时候,并不是立即就执行。

线程的任务都封装在特定的区域中,比如主线程运行的任务在main方法中,main()的方法体就是主线程的线程执行体;而垃圾回收线程在收垃圾时,都会运行finalize().

编程使用多线程的优点:

1、进程之间不能共享内存,但线程之间共享内存非常容易。

2、系统创建进程时,需要为该进程重新分配系统资源,但创建线程代价小得多,因此使用多线程来实现多任务并发比多进程的效率高。

3、Java语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方法,从而简化了java的多线程编程。

第二部分Thread类

1、Java使用Thread类代表线程,所有线程对象都是必须是Thread类或其子类的实例。


//由于Thread类是java.lang包下的类,因此我们在这里没有导包。
public class ThreadDemo extends Thread {
private int i;
public void run(){
for(;i<5;i++){
//getName()该方法是Thread类的实例方法,该方法返回调用该方法的线程名字。
System.out.println(Thread.currentThread().getName()+""+i);
System.out.println(this.getName()+"\t"+i);
System.out.println(getName()+"\t"+"\t"+i);
}
}
public static void main(String [] args){
//currentThread()为Thread类的静态方法,该方法总是返回当前正在执行的线程对象。
System.out.println(Thread.currentThread().getName());
new ThreadDemo().start();
new ThreadDemo().start();
//在默认情况下,主线程的名字为main,用户启动的多个线程的名字一次为Thread-0、Thread-1、Thread-2...等。

}
}


输出结果:

main

Thread-00

Thread-0 0

Thread-0 0

Thread-01

Thread-0 1

Thread-10

Thread-0 1

Thread-1 0

Thread-02

Thread-1 0

Thread-0 2

Thread-11

Thread-0 2

Thread-1 1

Thread-03

Thread-1 1

Thread-0 3

Thread-12

Thread-0 3

Thread-04

Thread-0 4

Thread-0 4

Thread-1 2

Thread-1 2

Thread-13

Thread-1 3

Thread-1 3

Thread-14

Thread-1 4

Thread-1 4

该程序继承了Thread类,并且实现了他的run()方法,该run()方法里的代码执行流就是该线程所需要完成的任务。这里一共有三个线程。一个是主线程,两个是子线程。

this.getName()调用的是堆里面的thread-0;

Thread.currentThread.getName()指向的是栈内存中Thread-0多线程区域的。;

因此如果直接在主方法中,用对象名调用run()的话,Thread.currentThread.getName()就会输出的是主线程的名字:main了。

start()和run()的区别:

调用start()方法,可以启动线程,让线程去执行run()中的任务。

调用run()方法,则仍是主线程在运行,线程并未开启,执行run()的是主线程,而不是子线程。

2、Runnable接口

Thread类实现了Runnable接口。我们在定义Runnable接口的实现类时,需要重写该接口的run()方法,该方法的方法体同样是该线程的线程执行体。Runnable接口实现了任务与线程分离的思想。也就是采用Runnable接口的方式创建的多个线程可以共享线程的实例属性。

创建线程的第二种方式:

1、定义一个类实现新Runnable。

2、覆盖Runnable接口中的run方法,将线程要运行的任务代码存储到该方法中。

3、通过Thread类创建线程对象,并将实现了Runnable接口的对象作为Thread类的构造函数的参数进行传递。

4、调用Thread类的start方法,开启线程。

class SaleTickets implements Runnable{
private int tickets=100;
public void run(){
while(true){
if(tickets>0){
System.out.println(Thread.currentThread.getName()+"*****"+tickets--);
}
}
}
}

class TicketDemo{
public static void main(String   []args){
SaleTickets st=new SaleTickets();
Thread t1=new Thread(st);
Thread t2=new Thread(st);
Thread t3=new Thread(st);
Thread t4=new Thread(st);
t1.start();
t2.start();
t3.start();
t4.start();
}
}


线程安全不安全?

当一个线程在操作数据时,其他的线程参与了运算,造成了数据的错误,这就是线程不安全。只要保证多条操作共享数据的代码在某一时间段,被一条线程所执行,在执行期间不允许其他线程参与运算。

第三部分 反射

反射:就是把java类中的各种成分映射成相应的java类。

java程序中的许多对象在运行时都会出现两种类型,编译时类型和运行时类型。比如代码People p=new Student();这里产生了一个变量p,该变量在编译时期类型为People,在运行时期类型为Student。

Class和class的区别:

在java程序中,java中的类用于描述一类事物的共性,也就是class,比如class People{};这个People类中有名字,年龄等属性,有吃饭睡觉等方法,还有构造函数。

Class指的是java程序中的各个java类是属于同一类事物,都是java程序的类,这些类成为Class。比如动物对于的是Animal类,java类对应的就是Class。也就是Class是java程序各个java类的总称,它是反射的基石,通过Class类来使用反射。

获取Class对象的三种方式:

1、使用Class类的forName(String clazzName)静态方法。该方法需要传入字符串参数,该字符串参数的值是某个类的全限定类名(必须添加完整包名);

2、调用某个类的class属性来获取该类对应的Class对象。例如Person.class将会返回Person类对应的Class对象。

3、调用某个对象的getClass()方法。该方法时java.lang.Object类中的一个方法,所以所有的java对象都可以调用该方法,该方法将会返回该对象所属类对应的Class对象。

第二种方法优点:代码更安全,程序性能更好。

一、从Class中获取信息:

1、获取Class对应类所包含的构造器:

Constructor<T> getConstructor(Class<?>...parameterTypes):返回此Class对象对应类的指定public构造器。

Constructor<?> [] getConstructors():返回此Class对象对应类的所有public构造器。

Constructor<T>getDeclaredConstructor(Class<?>...parameterTypes):返回此Class对象对应类的指定构造器。

Constructor<?>[] getDeclaredConstructors():返回此Class对象对应类的所有构造器。

2、获取Class对应类所包含的方法

Method getMethod(String name,Class<?>...parameterTypes):返回此Class对象对应类的指定public方法

Method [] getMethod():返回此Class对象所表示的类的所有public方法。

Method getDeclaredMethod(String name,Class<?>...parameterTypes):返回此Class对象对应类的指定方法, 与方法的访问权限无关。

Method [] getDeclaredMethod():返回此Class对象所表示类的所有public方法。

3、访问Class对应类所包含的成员变量

Field getField(String name):返回此Class对象对应类的指定public Filed。

Filed[] getField():返回此Class对象对应类的多有public Fileld。

Field getDeclaredField(String name):返回此Class对象对应类指定的Filed,与Field访问权限无关。

Field[] getDeclaredFields():返回此Class对象对应类的全部Field。

二、用反射生成并操作对象

通过反射来生成对象的两种方式:

1、使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求该Class对象的对应类有默认构造器,而执行newInstance()方法时,实际上是利用默认构造器来创建该类的实例。

2、使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求该Class对象的对应类有默认构造器,而执行newInstance()方法时,实际上是利用默认构造器来创建该类的实例。

1、调用方法:

当获得某个类对应的Class对象后,就可以通过该Class对象的getMethods()方法或者getMethod()方法来获取全部方法或指定方法——这两个方法的返回值是Method对象组,或者Method对象。

2、访问属性值:

通过Class对象的getFields()或getField()方法可以获取该类所包括的全部Field(属性)或指定Field.Field提供了如下两组方法来访问属性:

1).getXxx(Object obj):获取obj对象该Field的属性值。此处的Xxx对应8个基本类型,如果该属性的类型是引用类型则取消get后面的Xxx。

2).setXxx(Object obj,Xxx val):将obj对象的该Field设置为val值。此处的Xxx对应8个基本类型,如果该属性的类型是引用类型则取消set后面的Xxx。

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: