1.包 package (包名的所有字母小写)
1.对类文件进行分类管理
2.给类提供多层命名空间
3.写在程序文件的第一行
4.类名的全称是: 包名.类名
5.包也是一种封装形式
总结:1.包与包之间进行访问,被访问的包中的类以及类中的成员,需要被public修饰
2.不同包中的子类还可以直接访问父类中被protected权限修饰的成员
3.包与包之间可以使用的权限只有两种,public和protected
权限 public protected default private
同一个类中 OK OK OK OK
同一个包中 OK OK OK NO
子类 OK OK NO NO
不同包中 OK NO NO NO
为了简化类的书写,使用一个关键字 import
import导入的是包中的类,建议不要写通配符*,需要用到包中的哪个类,就导入哪个类,建议定义包名不要重复,可以使用url来完成定义,因 为url是唯一的。
例如: package cn.itcast.demo
2.jar包
2.多线程
进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行。
一个进程中至少有一个线程
jvm启动的时候会有一个进程 java.exe,该进程至少有一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中,该线程称之为 为主线 程。
扩展:其实更细节说明jvm,jvm启动不止一二线程,还有一个负责垃圾回收机制的线程
3.如何在自定义的代码中,自定义一个线程呢?
通过对api的查找,java已经提供了对线程这类事物的描述,就是Thread类
1.创建线程的第一种方式:继承Thread类
步骤:1.定义类继承Thread
2.重写Thread类中的run方法
3.调用线程的start方法(该方法两个作用:启动线程、调用run方法)
发现运行结果每次都不同,因为每个线程都获取cpu的执行权。cpu执行到谁,谁就运行。明确一点,在某一个时刻,只能有一个程序在运 行(多核除外),cpu在做着快速的切换,已达到看上去是同时运行的效果。我们可以形象把多线程的运行行为看做在互相抢夺cpu的执行 权,这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多久,cpu说的算。
1.为什么要重写run方法呢?
Thread类用于描述线程。该类定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法。
也就是说Thread类中的run方法用于存储线程要运行的代码。
2.线程都有自己默认的名称。 Thread-编号,该编号从0开始
static Thread currentThread(); 获取当前线程对象
getName(); 获取线程名称
设置线程名称 setName()或者构造函数
需求:简单的卖票程序(多个窗口同时卖票)
2.创建线程的第二种方式:实现Runnable接口
步骤:
1.定义类实现Runnable接口
2.重写Runnable接口中的run方法,将线程要运行的代码存放在该方法中
3.通过Thread类建立线程对象
4.将Runnabloe接口的子类对象作为实际参数传递给Thread类的构造函数
为什么要将Runnable接口的子类对象传递给Thread的构造函数呢?因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去执行
指定对象的run方法,就必须明确该方法所属对象
5.调用Thred类的start方法,开启线程并条用Runnable接口子类的run方法
3.实现方式和继承方式有什么区别呢?
实现方式好处:避免了单继承的局限性,在定义线程时,建议使用实现方式
两种方式区别:
继承Thread:线程代码存放于Thread子类run方法中
实现Runnable: 线程代码存放于接口的子类的run方法中
4.多线程的安全问题
通过分析,发现打印出了0、-1、-2等错票。多线程的运行出现了安全问题。
问题的原因:当多条语句在操作同一个线程共享数据时,一条线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误
解决办法:对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程都不可以执行。
java对于多线程的安全问题提供了专业的解决方式,就是同步代码块。
synchronized(对象)
{
需要被同步的代码;
}
1.对象如同锁,持有锁的线程可以在同步中执行,没有持有锁的线程即使获取cpu的执行权,也进不去。火车上的卫生间-----经典!!
2.同步的前提
1.必须要有两个或者两个以上的线程
2.必须是多个线程使用同一个锁
必须保证同步中只能有一个线程在运行
好处:解决了多线程的安全问题
弊端:多个线程需要判断锁,较为消耗资源
同步函数使用的是哪一个锁呢? 函数需要被对象调用,那么函数都有一个所属对象引用,就是this,所以同步函数使用的锁是this
如果同步函数被静态修饰后,使用的锁是什么呢?通过验证,发现不再是this,因为静态方法中也不可以定义this,静态进内存时,内存中没有本类
对象,但是一定有该类对应的字节码文件对象 类名. class, 该对象的类型是Class.静态的同步方法,使用的锁是该方法所在类的字节码文件对象类名.class
死锁:同步中嵌套同步
5.线程间通讯:其实就是多个线程在操作同一个资源,但是操作的动作不同。
等待唤醒机制: wait; notify(); notifyAll();
都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要使用在同步中,因为只有同步才具有锁。
为什么这些操作线程的方法要定义Object类中呢?因为这些方法在操作同步中线程时,都必须要标识它们所操作线程只有的锁,只有同一 个锁上的被等待线程,可以被同一个锁上notify 唤醒。不可以对不同锁上得线程进行唤醒。
也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法,定义Object类中。
1.stop方法已经过时,如何停止线程?只有一种,run方法结束。开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让 run方法结束,也就是线程结束。
特殊情况:当线程处于了冻结状态,就不会读取到标记,那么线程就不会结束。
当没有指定的方式让冻结的线程恢复到运行状态时,这是需要对冻结进行解除,强制让线程恢复到运行状态中来,这样就可 以操作标记让线程结束。Thread类提供该方法 interrupt();
2.join的特点:当A线程执行到了B线程的join方法时,A线程就会等待,等待B线程都执行完,A才会执行。join可以用来临时加入线程执行