1、线程
Thread类:
public final String getName():返回该线程的名称
public final void setName(String name):改变线程名称,使之与参数 name
相同
getThreadGroup():返回该线程所属的线程组。
线程控制:
public static void sleep(long millis):线程休眠
public final void join():线程加入( 等待该线程终止)
public static void yeild():线程礼让(暂停当前正在执行的线程对象,并执行其他线程。)
public final void setDaemon(boolean on):后台线程
public final void stop(): 已过时。 该方法具有固有的不安全性。用 Thread.stop 来终止线程将释放它已经锁定的所有监视器
public void interrupt(): 中断线程。
多线程的实现方案:
1)继承Thread类
步骤
A:自定义类MyThread继承Thread类。
B:MyThread类里面重写run()
C:创建对象
D:启动线程
public class MyThread extends Thread {
public void run() {
for (int x = 0; x < 200; x++) {
System.out.println(x);
}
}
}
public class MyThreadDemo {
public static void main(String[] args) {
// run():仅仅是封装被线程执行的代码,直接调用是普通方法
// start():首先启动了线程,然后再由jvm去调用该线程的run()方法。
// IllegalThreadStateException:非法的线程状态异常
// 创建两个线程对象
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
// 启动线程
my1.start();
my2.start();
}
}
2)实现Runnable接口(实现接口可以避免java单继承带来的局限性)
步骤:
A:自定义类MyRunnable实现Runnable接口
B:重写run()方法
C:创建MyRunnable类的对象
D:创建Thread类的对象,并把C步骤的对象作为构造参数传递
public class MyRunnable implements Runnable {
public void run() {
for (int x = 0; x < 100; x++) {
// 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用
System.out.println(Thread.currentThread().getName() + ":" + x);
}
}
}
public class MyRunnableDemo {
public static void main(String[] args) {
// 创建MyRunnable类的对象
MyRunnable my = new MyRunnable();
// 创建Thread类的对象,并把C步骤的对象作为构造参数传递
// Thread(Runnable target, String name)
Thread t1 = new Thread(my, "aa");
Thread t2 = new Thread(my, "bb");
t1.start();
t2.start();
}
}
解决线程安全问题:
1)同步代码块:
synchronized(对象){
需要同步的代码;
}
同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。多个线程必须是同一把锁。
public class SellTicket implements Runnable {
// 定义100张票
private int tickets = 100;
//创建锁对象
private Object obj = new Object();
@Override
public void run() {
while (true) {
synchronized (obj) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票");
}
}
}
}
}
2)同步方法:把同步加在方法上
普通方法(同步对象是this)
private synchronized void sellTicket() {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票 ");
}
}
public void run() {
while (true) {
if(x%2==0){
synchronized (this) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票 ");
}
}
}else {}
静态方法的锁对象是:类的字节码文件对象
private static synchronized void sellTicket() {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票 ");
}
}
}
public void run() {
while (true) {
if(x%2==0){
synchronized (SellTicket.class) {//这里不可能是this,因为静态中没有this 静态是随着类的加载而加载,首先进内存的是类的字节码文件
if (tickets > 0) {
try {
Thread.sleep(100);
Lock锁
void lock():获取锁。(如果锁不可用,出于线程调度目的,将禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态。)
void unlock():释放锁
public class SellTicket implements Runnable {
// 定义票
private int tickets = 100;
// 定义锁对象
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
// 加锁
lock.lock();
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票");
}
} finally {
// 释放锁
lock.unlock();
}
}
}
}
线程池:(线程池里的每一个线程代码结束后并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用)
程序启动一个新线程的成本很高,因为涉及到与操作系统的交互,而使用线程池可以很好的提高性能
JDK5新增了Executors工厂类来产生线程池
方法:
public static ExectorService newCachedThreadPool():开启具有缓存功能的线程池
public static ExectorService newFixedThreadPool(int nThreads):创建指定数量的线程池
public static ExectorService newSingleThreadExector():创建一个
这些方法的返回值是ExectorsService对象,该对象表示一个线程池,可以执行Runnable对象和Callable对象代表的线程
public static void main(String[] args) {
// 创建一个线程池对象,控制要创建几个线程对象。
// public static ExecutorService newFixedThreadPool(int nThreads)
ExecutorService pool = Executors.newFixedThreadPool(2);
// 可以执行Runnable对象或者Callable对象代表的线程
//Future<?> submit(Runnable task): 提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
// <T> Future<T> submit(Callable<T> task): 提交一个返回值的任务用于执行,返回一个表示任务的未决结果Future。
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
//结束线程池
pool.shutdown();//如果不加结束语句,那么线程执行完毕后重新返回池中,以供其他人使用
}
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(Thread.currentThread().getName() + ":" + x);
}
}
}
定时器:
Timer:(extends Object)一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。
Timer()
创建一个新计时器。
schedule(TimerTask task, long delay)
安排在指定延迟后执行指定的任务。
schedule(TimerTask task, long delay, long period)
安排指定的任务从指定的延迟后开始进行重复的固定延迟执行
cancel()
终止此计时器,丢弃所有当前已安排的任务。
TimerTask(extends Object implements Runnable)
TimerTask()
创建一个新的计时器任务
run()
此计时器任务要执行的操作。
cancel()
取消此计时器任务。
jvm虚拟机的启动是单线程的还是多线程的?
多线程的。
原因是垃圾回收线程也要先启动,否则很容易会出现内存溢出。
现在的垃圾回收线程加上前面的主线程,最低启动了两个线程,所以,jvm的启动其实是多线程的。
2、设计模式
1)简单工厂模式(静态工厂方法模式):定义一个具体的工厂类负责创建一些类的实例
缺点:静态工厂负责所有对象的创建,若有新的对象添加或者某些对象的创建方式不同i,就需要不断的修改工厂,不利于后期的维护
public abstract class Animal {
public abstract void eat();
}
//动物工厂
public class AnimalFactory {
//工厂模式的明显特点是 构造方法私有,其他方法是静态的
//构造方法私有只有,外界就不能通过new来创建对象。
private AnimalFactory() {//下面是静态方法 ,这里构造私有?是因为可以通过类名调用??
}
//原始版
// public static Dog createDog() {
// return new Dog();
// }
// public static Cat createCat() {
// return new Cat();
// }
//下面是改进版
public static Animal createAnimal(String type) {
if ("dog".equals(type)) {
return new Dog();
} else if ("cat".equals(type)) {
return new Cat();
} else {
return null;
}
}
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
public class AnimalDemo {
public static void main(String[] args) {
// 具体类调用
Dog d = new Dog();
d.eat();
Cat c = new Cat();
c.eat();
System.out.println("------------");
//构造方法私有之后,想要创建对象只能通过工厂类来创造
//返回的对象可以是该类对象或者是该类的子类对象
// 工厂有了后,通过工厂给造
// Dog dd = AnimalFactory.createDog();
// Cat cc = AnimalFactory.createCat();
// dd.eat();
// cc.eat();
// System.out.println("------------");
// 工厂改进后
Animal a = AnimalFactory.createAnimal("dog");
a.eat();
a = AnimalFactory.createAnimal("cat");
a.eat();
// NullPointerException当工厂中没有这种动物的时候将会报空指针异常
a = AnimalFactory.createAnimal("pig");
if (a != null) {//所以这里最好要加上判断是否为null
a.eat();
} else {
System.out.println("对不起,暂时不提供这种动物");
}
}
}
2)工厂方法模式:抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现------客户端不再需要负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只要增加一个具体的类和具体的工厂类即可,不影响已有代码,利于后期维护
//抽象动物类
public abstract class Animal {
public abstract void eat();
}
//工厂接口
public interface Factory {
public abstract Animal createAnimal();
}
//猫工厂类实现了工厂类
public class CatFactory implements Factory {
@Override
public Animal createAnimal() {
return new Cat();
}
}
//狗工厂类实现了工厂类
public class DogFactory implements Factory {
@Override
public Animal createAnimal() {
return new Dog();
}
}
//猫类继承动物类
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
//狗类实现了动物接口
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
public class AnimalDemo {
public static void main(String[] args) {
// 需求:我要买只狗
Factory f = new DogFactory();
Animal a = f.createAnimal();
a.eat();
System.out.println("-------");
//需求:我要买只猫
f = new CatFactory();
a = f.createAnimal();
a.eat();
}
}
3)单例设计模式:保证类在内存中只有一个对象。
* 如何保证类在内存中只有一个对象呢?
* A:把构造方法私有:为的是不让外界造对象
* B:在成员位置自己创建一个对象
* C:通过一个公共的方法提供访问
饿汉式:(不会出问题)
public class Student {
// 构造私有为的是不让外界造对象
private Student() {
}
// 静态方法只能访问静态成员变量,加静态
// 为了不让外界直接访问修改这个值,加private
private static Student s = new Student();
// 提供公共的访问方式
// 为了保证外界能够直接使用该方法,加静态
public static Student getStudent() {
return s;
}
}
public class StudentDemo {
public static void main(String[] args) {
// Student s1 = new Student();
// Student s2 = new Student();
// System.out.println(s1 == s2); // false 因为创建的是不同的对象
// 通过单例得到对象保证类在内存中只有一个对象。
Student s1 = Student.getStudent();
Student s2 = Student.getStudent();
System.out.println(s1 == s2); // true内存中只有一个对象
System.out.println(s1); // cn.itcast_03.Student@175078b
System.out.println(s2);// cn.itcast_03.Student@175078b
}
}
懒汉式:(会出问题)
A:懒加载(延迟加载)
B:线程安全问题
public class Teacher {
private Teacher() {
}
private static Teacher t = null;
public synchronized static Teacher getTeacher() {//因为有线程安全问题,所有要加同步
// t1,t2,t3
if (t == null) {
//t1,t2,t3
t = new Teacher();
}
return t;
}
}
public class TeacherDemo {
public static void main(String[] args) {
Teacher t1 = Teacher.getTeacher();
Teacher t2 = Teacher.getTeacher();
System.out.println(t1 == t2);
System.out.println(t1); // cn.itcast_03.Teacher@175078b
System.out.println(t2);// cn.itcast_03.Teacher@175078b
}
}
4)模板设计模式:
就是定义一个算法的骨架,而将具体的算法延迟到子类中来实现
public abstract class GetTime {
// 需求:请给我计算出一段代码的运行时间
public long getTime() {
long start = System.currentTimeMillis();
code();//只有这一块是变化的
long end = System.currentTimeMillis();
return end - start;
}
public abstract void code();//在定义的时候不知道里面会是什么,相当于是一个模板
}
public class ForDemo extends GetTime {
@Override
//需要什么样的方法,就在重写的code()里面写什么代码
public void code() {
for (int x = 0; x < 100000; x++) {
System.out.println(x);
}
}
}
public class GetTimeDemo {
public static void main(String[] args) {
GetTime gt = new ForDemo();
System.out.println(gt.getTime() + "毫秒"); //在父接口中走code(),但是由于父类中该方法是抽象的,所有走子类重写的code方法 ,走过之后再回到父类中走没有走的代码
}
}
5)装饰设计模式
就是使用被装饰类的一个子类的实例,在客户端jangle这个子类的实例交给装饰类。是继承的替代方案
public interface Phone {
public abstract void call();
}
public class IPhone implements Phone {
@Override
public void call() {
System.out.println("手机可以打电话了");
}
}
//抽象的手机装饰类
public abstract class PhoneDecorate implements Phone {
private Phone p;
public PhoneDecorate(Phone p) {
this.p = p;
}
@Override
public void call() {
this.p.call();//PhoneDecorate中的call调用的是传过来的具体手机类的call
}
}
public class MusicPhoneDecorate extends PhoneDecorate {
public MusicPhoneDecorate(Phone p) {
super(p);
}
@Override
public void call() {
super.call();
System.out.println("手机可以听音乐");
}
}
public class RingPhoneDecorate extends PhoneDecorate {
public RingPhoneDecorate(Phone p) {
super(p);
}
@Override
public void call() {
System.out.println("手机可以听彩铃");
super.call();//这里的super指的是PhoneDecorate 调用PhoneDecorate中的call
}
}
public class PhoneDemo {
public static void main(String[] args) {
Phone p = new IPhone();
p.call();
System.out.println("------------");
// 需求:我想在接电话前,听彩铃
PhoneDecorate pd = new RingPhoneDecorate(p);
pd.call();
System.out.println("------------");
// 需求:我想在接电话后,听音乐
pd = new MusicPhoneDecorate(p);
pd.call();
System.out.println("------------");
// 需求:我要想手机在接前听彩铃,接后听音乐
// 自己提供装饰类,在打电话前听彩铃,打电话后听音乐
pd = new RingPhoneDecorate(new MusicPhoneDecorate(p));
pd.call();
System.out.println("----------");
// 我们在IO流中的使用
// InputStream is = System.in;
// InputStreamReader isr = new InputStreamReader(is);
// BufferedReader br = new BufferedReader(isr);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(
System.out)));
Scanner sc = new Scanner(System.in);
}
}
3、反射
java反射机制是在运行状态中国,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能调用它的以恶方法和属性。这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想剖析一个类,首先要获取该类的字节码文件对象。
获取Class类型的对象:
1)Person p = new Person();
Class c = p.getClass();
2)Class c2 = Person.class();
3)Class c3 = Class.forName("Person");
获取构造方法:
getConstructors:
返回一个包含某些 Constructor
对象的数组,这些对象反映此 Class
对象所表示的类的所有公共构造方法。
getDeclaredConstructors:
返回 Constructor
对象的一个数组,这些对象反映此 Class
对象表示的类声明的所有构造方法。
创建对象:
newInstance():
创建此 Class 对象所表示的类的一个新实例。
invoke():
public Object invoke(Object obj,Object... args)
返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数
获取所有成员:
getFields:
返回一个包含某些 Field
对象的数组,这些对象反映此 Class
对象所表示的类或接口的所有可访问公共字段
getDeclaredField:
返回一个 Field
对象,该对象反映此 Class
对象所表示的类或接口的指定已声明字段。
获取单个成员:
getField
getDeclaredField
修改成员的值:
set(Object obj,Object value)
将指定对象变量上此Filed对象表示的字段设置为指定的新值
获取所有方法:
getMethods
getDeclaredMethods
获取单个方法:
getMethod
getDeclaredMethod
暴力访问:
method.setAccessible(true)
举例:
public class Person {
private String name;
int age;
public String address;
public Person() {
}
private Person(String name) {
this.name = name;
}
Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public void show() {
System.out.println("show");
}
public void method(String s) {
System.out.println("method " + s);
}
public String getString(String s, int i) {
return s + "---" + i;
}
private void function() {
System.out.println("function");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", address=" + address
+ "]";
}
}
/*
* 通过反射获取构造方法并使用。
*/
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
Constructor con = c.getConstructor();// 返回的是构造方法对象
// 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
Object obj = con.newInstance();
System.out.println(obj);
Person p = (Person)obj;
p.show();
}
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
// 获取带参构造方法对象
Constructor con = c.getConstructor(String.class, int.class,String.class);
// 通过带参构造方法对象创建对象
// public T newInstance(Object... initargs)
Object obj = con.newInstance(“xxx", 27, "北京");
System.out.println(obj);
}
}
//通过反射获取私有构造方法并使用
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
// 获取私有构造方法对象
// NoSuchMethodException:没这个方法异常
// 原因是一开始我们使用的方法只能获取公共的,下面这种方式就可以了。
Constructor con = c.getDeclaredConstructor(String.class);
// 用该私有构造方法创建对象
// IllegalAccessException:非法的访问异常。
// 暴力访问
con.setAccessible(true);// 值为true则指示反射的对象在使用时应该取消Java语言访问检查。
Object obj = con.newInstance("xx");
System.out.println(obj);
}
}
给一个ArrayList<Integer>的一个对象,想向这个集合中添加一个字符串数据,如何实现??
//创建集合对象
ArrayList<Integer> array = new ArrayList<Integer>();
//array.add("hello");不行。因为类型不同,不能添加
//用反射实现
Class c = array.getClass();
Method m = c.getMethod("add",Object.class);
m.invoke(array,"hello");//调用array的add方法,传入的值是hello
syso(array);