您的位置:首页 > 编程语言 > Java开发

Java基础12--包--多线程

2013-12-20 16:26 302 查看

12-1,包-概述

1,定义格式:package mypack;包名都是小写。
2,包能对类文件进行分类管理,给类提供多层命名空间。多层命名空间指的是类的所属,比如一台电视,中国可以生产,美国也可以生产,这时就要说明这时中国生产的电视还是没过生产的电视,否则就会产生歧义。
包应该定义在程序文件的第一行。
类名的全称是:包名.类名
包也是一种封装形式。
3,

package mypack;
class PackageDemo {
public static void main(String[] args) {
System.out.println("Hello package");
}
}


这个程序在用命令行编译时不会报错,但在运行时会报错,因为定义了包,这时类就有了所属,必须在目录下创建与报名相同的文件夹,并把编译出的.class文件放入才能运行通过,运行时输入Javamypack.PackageDemo,就可以执行。

4,手动创建文件夹会很麻烦,在编译的时候可以自动生成文件夹。
方法是:javac –d . PackageDemo.java,在当前目录下生成mypack文件夹并在这个文件夹中生成PackageDemo.class文件,运行时输入java mypack.PackageDemo就行。
若文件夹中还有文件夹,就是包中有包,在定义包时的格式为:
Package mypack.haha.hehe.xixi;编译时:javac –d .PackageDemo.java,就可以生成一层一层的文件夹,运行时,javamypack.haha.hehe.xixi.PackageDemo就可以。

12-2,包-包之间的访问-protected

1,第一个文件:
package mypack;
class PackageDemo {
public static void main(String[] args) {
DemoA a = new DemoA();
a.show();
System.out.println("Hello package!");
}
}

第二个文件:
package packa;
public class DemoA{
public void show() {
System.out.println("demo a show run...");
}
}

编译顺序问题:如果两个类在同一个包中,先编译PackageDemo是没问题的,但在不同的包中,必须先编译DemoA,再编译PackageDemo类,因为若先编译PackageDemo类,其中的DemoA类会找不到,因为编译时是在同包下找类的,而且创建对象时应该指定是哪个包中的DemoA,否则也会编译失败,即应该为:packa.DemoA a = newpacka.DemoA();
还要注意classpath的问题,路径不对会找不到文件。
2,访问权限问题:
包与包之间的类进行访问,被访问的包中的类必须是public的,被访问的包中的类的方法也必须是public的,若为默认权限,则相当于把类封装起来,无法访问。
3,一个包中的类继承另一个包中的类应注意的问题:
package packa;
public class DemoA extends packb.DemoB {
public void show() {
method();
System.out.println("DemoA show run...");
}
}

package packb;
public class DemoB {
protected void method() {
System.out.println("DemoB methdo run ... ");
}
}

DemoA继承了DemoB,A要使用B中的method方法,在不继承的情况下也可以使用,如:定义B中的method方法的权限为public,在A中定义:
packb.DemoB b = new packb.DemoB();
b.method();
但如果B中的方法是被protected修饰的,则必须继承才可以使用method方法,protected为保护权限。Protected一定程度上起到了封装的作用。

12-3,包-导入import

1,import是导入指定的包中的类用的。
如:
import packa.DemoA;//导入了packa包中的DemoA类
...
DemoA d = new DemoA(); //导入了这个包,就不用加包的前缀了
提示:import packa.*;是导入了packa包中的所有的类。
2,若packa\DemoA.class
Packa\abc\DemoABC.class
如果import packa.*;则只能导入DemoA.class而不能导入DemoABC.class,只能导入包中的类,不能导入包中的包,要用import packa.abc.*;导入。
3,导包的原则:用到哪个类就导入那个类。
一个Java文件只能有一个pacakge,但可以有多个import。
4,import是干什么用的?
是为了简化类名的书写用的。

12-4,jar包

1,jar是Java的压缩包,当文件夹很多时,用jar打包,类似于Windows的winrar工具。
2,在命令行输入jar可以查询jar的方法。
例如:输入jar –cf haha.jar pack
其中:haha是指定的压缩包名,pack是要压缩的文件夹名。
c:创建新的归档文件;
f:指定归档文件名
输入jar –cvf haha.jar pack
v:在标准输出中生成详细输出(也就是在压缩过程中做了什么事)

3,解压缩方法:
输入:jar-xvf haha.jar解压出pack文件夹和META-INF文件夹,后者是解压缩的清单文件,这个文件名是固定的:MANIFEST.MF。
4,如果把文件夹压缩了,在命令行可以直接执行里面的.class文件。先设置classpath为./haha.jar然后java pack.JarDemo即可。其实压缩以后就是给文件夹又多了一级目录,相当于D:\java\haha.jar\pack\JarDemo.class。

12-5,多线程-概述

进程:正在进行中的程序。
线程:就是进程中一个负责程序执行的控制单元(执行路径)。
一个进程中可以有多个执行路径,称之为多线程。
一个进程中至少有一个线程。
开启多个线程是为了同时运行多部分代码。
每个线程都有自己的运行内容。这个内容可以称为线程要执行的任务。

12-6,多线程-好处和弊端

好处:解决了多部分代码同时执行的问题。
弊端:线程太多会造成效率的降低。
其实应用程序的执行都是CPU在各个应用程序之间做着快速的切换来完成的,这个切换时随机的。

12-7,JVM中的多线程解析

JVM启动时就启动了多个线程,至少有两个线程是可以分析出来的。
(1)执行main函数线程
该线程的任务代码都定义在main函数中。
(2)负责垃圾回收的线程
Object类中的finalize方法可以对堆中产生的垃圾进行回收。
System.gc();方法启动垃圾回收器,调用finalize方法。

12-8,多线程-主线程运行示例

1,如果堆中产生了垃圾,垃圾回收器不会马上执行回收动作,当满足一定量时可能会溢出内存时才回收垃圾。
2,当一个程序出现占用时间多的程序块时(例如循环),这时它下面的代码就无法执行了,我们不希望浪费等待的时间,希望能继续执行后面的代码,提高效率,这时就需要把下面的代码单开一个线程来执行。

12-9,多线程-多线程创建的方式-继承Thread类

1,如何创建一个线程呢?
方式1:继承Thread类。
步骤:
(1)定义一个类继承Thread类。
(2)覆盖Thread类中的run方法。
(3)直接创建Thread的子类对象创建线程
(4)调用start方法开启线程并调用线程的任务run方法执行。
2,创建线程的目的是为了开启一条执行路径,去运行指定的代码和其他代码实现同时运行。而运行的代码就是这个执行路径的任务。
JVM创建的主线程的任务都定义在了主函数中。
而自定义的线程的任务在哪呢?
Threan类用于描述线程,线程是需要任务的。所以Thread类也对任务进行描述。这个任务就通过Thread类中的run方法来体现。也就是说,run方法就是封装自定义线程运行任务的函数。
run方法中定义的就是线程要运行的任务代码。
开启线程是为了运行指定代码,所以只有继承Thread类,并覆写run方法,将运行的代码定义在run方法中即可。
代码示例:
class Demo extends Thread { //第一步:继承Thread类
private String name;
Demo(String name) {
this.name = name;
}
public void run() { //第二步:覆盖run方法,run方法中写任务代码
for(int x=0;x<10;x++) {
System.out.println(name + "x = " + x);
}
}
}
class ThreadDemo {
public static void main(String[] args) {
Demo d1 = new Demo("wangcai"); //第三步:创建子类对象创建线程
Demo d2 = new Demo("xiaoqiang");
d1.start(); //开启线程,调用run方法
d2.start();
}
}

这个程序有3个线程,主线程,d1和d2的线程,如果在最后一行加上System.out.println(“over”);则三种打印结果时随机出现的。

12-10,多线程-Thread类中的方法&线程名称

1,可以通过Thread的getName方法获取线程的名称,格式是:Thread-编号(从0开始),
主线程的名字就是main。
2,获取当前正在执行线程的名字:Thread.currentThread().getName();
currentThread()方法为静态的,直接用类名调用。
如在上节的例子中的run方法中写上System.out.println(name+"...x="+x+"...name="+Thread.currentThread().getName());在d2.start();后写上System.out.println("over"+Thread.currentThread().getName());则会显示出Thread-0,Thread-1,main等名称。
3,Thread类中有构造函数Thread(Stringname),在Demo类中Demo(String name)中写上super(name)就可以显示自定义的线程名称,则以增强阅读性。
4,Demo类一继承Thread类,就用super自动调用Thread中的Thread(),而Thread()中定义了线程的名字,所以一继承,该线程就具有了名字,这就是线程名称的由来。

12-11,多线程运行图解

1,图示:



在栈中有3条执行路径,分别是main线程,Thread-0和Thread-1线程,三条路径互不影响,若主线程main因异常结束,其他两个线程继续执行。
主线程中的方法进入main的栈执行,Thread-0中run中的的方法在Thread-0的栈中执行,Thread-1中run中的方法在Thread-1的栈中执行,故三条线程互不影响。
2,代码示例:
class Demo extends Thread {
private String name;
Demo(String name) {
this.name = name;
}
public void run() {
int[] arr = new int[3];
System.out.println(arr[3]); //抛异常
for(int x=0;x<10;x++) {
System.out.println("...x="+x+"...name="+Thread.currentThread().getName());
}
}
}
class ThreadDemo {
public static void main(String[] args) {
Demo d1 = new Demo("wangcai");
Demo d2 = new Demo("xiaoqiang");
d1.start();
d2.start();
System.out.println(4/0); // 抛异常
for(int x=0;x<20;x++) {
System.out.println(x+"..."+Thread.currentThread().getName());
}
}
}

此程序执行结果会抛出Exception in thread main...;
Exception in thread Thread-0和Exception in threadThread-1三个异常,
这说明三个线程的执行互不影响。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: