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

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三个异常,

这说明三个线程的执行互不影响。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值