进程:由系统资源分配和调度的最小单元,而线程依赖于进程存在,程序执行的最小单位!
如果创建线程----必须有进程----->创建系统资源
* Java语言不能够创建系统资源, 借助于底层语言C语言来操作
* Java提供类Thread类
*
* 借助于Thread类如何实现 线程的创建?
*
*
* 并发:在一个时间点同时发生
* 并行:在一个时间段内同时发生
*
*
* 开发步骤:
* 1)自定义一个类 继承自 Thread(线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。 )
* 2)该子类应重写 Thread 类的 run 方法
* 3)创建当前子类对象,然后启动线程:start()而非run方法()
*
* 启动线程:使用start 方法
*成员方法:
* 设置线程名称
* public final void setName(String name)
* 获取线程名称:
* public final String getName()
public class ThreadDemo {
public static void main(String[] args) {
//创建子类对象
MyThread my = new MyThread() ;
//启动线程
//这个一线程对象将run方法调用两次
// my.run();
// my.run();
my.setName("杨德财");
my.start(); //调用start方法,是通过jvm调用run方法
//my.start(); //IllegalThreadStateException:非法状态异常
MyThread my2 = new MyThread() ;
my2.setName("高圆圆") ;
my2.start();
}
}
public static void yield():暂停当前正在执行的线程,执行其他线程!
public final void join()
* throws InterruptedException :等待该线程终止
Thread类的常量字段表
* public static final int MAX_PRIORITY 10
* public static final int MIN_PRIORITY 1
* public static final int NORM_PRIORITY 5 :默认值
*
* public final void setPriority(int newPriority)设置优先级
* public final int getPriority()
*
*
* 优先级越大的线程,抢占CPU的执行权(cpu一点点时间片,可以高效的进行切换)的资格大
* 优先级越小的线程:抢占CPU的执行权越小!
*
* 线程的执行具有随机性!默认是5
tp1.setPriority(10);
tp2.setPriority(1);
System.out.println(tp3.getPriority());//5
Java语言不能开启多线程
.什么是进程,什么是线程
进程:
系统资源分配和调度的基本单元! (程序的"实体")
线程必须依托于进程存在,是程序执行的基本单位!
一个进程有有很多个线程组组成的,一个线程组中包含很多线程(是线程的集合!)
多线程---每个线程的执行具有随机性,在互相强制CPU的执行权(才具备执行资格)
2.创建多线程的方式?请阐述步骤
方式1:
使用继承关系:
1)自定义一个类,继承自Thread类(线程类)
2)重写run方法: 通过启动线程,jvm调用run方法
3)在用户线程(main)创建当前类对象,启动线程:start()
3.Map集合的遍历方式
两种
1)获取所有的键的集合:Set<K> keySet() (推荐)
遍历所有的键---V get(Object K):通过键获取值
2)获取所有的键值对对象:Set<Map.entry<K,V>> entrySet()
遍历所有键值对对象:通过键值对对象:获取键和值
K getKey()
V getValue()
4.自然排序和比较器排序在TreeSet<E>集合中如何实现
如果TreeSet<E>要实现自然排序,通过无参构造方法创建当前类对象TreeSet<E>()
必须满足条件:当前存储的类型必须实现接口Comparable接口
重写comparable接口中的compareTo(T t)方法
如果TreeSet<E>实现比较器排序:通过有参构造创建当前类对象TreeSet<E>(Comparator<E> com)
1)自定义类实现Comparator<E>,重写Comparator接口的compare(T t1,T t2)
2)创建当前类对象的时候,直接使用接口匿名内部类的方式
形式参数:
new Comparator<E>(){
重写compare(T t1,T t2) {
排序规则
}
} ;
5.final,finalize的区别?
final:状态修饰符
修饰类,不能被继承
修饰方法:不能被重写
修饰变量:是一个常量
finalize:是Object类的一个方法:当前创建对象的时候,如果这个对象没有更多引用,使用完毕了,
等待GC来回收不用的对象,启动GC,会调用finalize()方法来回收,释放被占用的空间!
GC垃圾回收算法
JVM优化机制
SQL优化(SQL调优)
web服务器调优
多线程实现方式1: 继承关系
SellTicket st1 = new SellTicket() ;
SellTicket st2 = new SellTicket() ;
SellTicket st3 = new SellTicket() ;
//设置线程名称
st1.setName("窗口1") ;
st2.setName("窗口2") ;
st3.setName("窗口3") ;
//启动线程
st1.start() ;
st2.start() ;
st3.start();
三个栈指向三个堆:分别在出售100张票 "没有数据共享"
继承关系具有局限性--->重写run方法----->Thread类的run---->通过实现Runnable接口的run 方法
不仅仅继承run方法,还将其他无关方法继承过来,不利于功能的扩展! (体现不出来:面向接口编程)
多线程实现方式2: (推荐)
"资源共享"
每一个线程都在使用同一个对象 st(SellTicket对象的引用) 体现出 "面向接口编程"
静态代理 模式
最大特点:真实角色和代理类都必须实现同一个接口!
代理类 对真实角色的功能进行方法增强!
代理类
真实角色
SellTicket 实现Runnable接口 完成run方法重写
Thread类 本身实现Runnable接口 完成run方法重写
SellTicket st = new SellTicket() ;
//创建多个线程类对象,将资源共享类作为参数传递
Thread t1 = new Thread(st,"窗口1") ;
Thread t2 = new Thread(st,"窗口2") ;
Thread t3 = new Thread(st,"窗口3") ;
//启动线程
t1.start();
t2.start();
t3.start();
多线程的实现方式2 实现关系(Runnable) (重点)
*
* 步骤:
* 1)自定义一个类,实现Runnable接口,重写run方法
* 2)在用户线程(main)创建当前"资源类"对象
* 然后创建Thread类对象,将"资源类"对象作为参数传递
*
* public Thread(Runnable target,String name)
* 3)分别启动线程
*
*
* //Thread类的静态功能
* public static Thread currentThread():表示正在执行的线程对象的引用
public class ThreadDemo {
public static void main(String[] args) {
//创建资源类对象
MyRunnable my = new MyRunnable() ;//共享资源
//创建线程类对象
Thread t1 = new Thread(my,"t1") ;
Thread t2 = new Thread(my,"t2") ;
Thread t3 = new Thread(my,"t3") ;
//启动线程
t1.start();
t2.start();
t3.start();
}
}
实现runnable接口
public class MyRunnable implements Runnable{
电影院有三个窗口,总共100张票,使用多线程模拟!
public class SellTicket extends Thread{
//有100张票
public static int tickets = 100 ;
//创建一个把锁
private Object obj = new Object() ;
@Override
public void run() {
//模拟一直有票
while(true){
synchronized (obj){
//加入网络延迟,睡眠100毫秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(tickets>0){
System.out.println(getName()+"正在出售第"+tickets+"张票");
tickets -- ;
}else{
break ;
}
}
}
}
}
public class SellTicketDemo {
public static void main(String[] args) {
//创建三个线程
SellTicket st1 = new SellTicket() ;
SellTicket st2 = new SellTicket() ;
SellTicket st3 = new SellTicket() ;
//设置线程名称
st1.setName("窗口1") ;
st2.setName("窗口2") ;
st3.setName("窗口3") ;
//启动线程
st1.start() ;
st2.start() ;
st3.start();
}
}
v
线程的执行:具有"原子性操作": tickets-- (线程的随机性导致的)
//t1先进来, 记录以前的值:100
//在t1记录100数据的时候,准备--的时候,t2进来,可能将t1之前记录的100值输出,100 出现同票
//第二种情况:出现了负票
//当前t1线程---第2张票
//睡眠100毫秒
//t3线程抢占到--->(将t1线程的2记录---完成--)第1张票
//t1,t2,t3 ---->t2先抢占到 ---->记录之前1,--完成后,变成0张票
//当前内存中记录值还没输出0的时候,t1抢占到之后,记录t2记录0张票, t1的票数--, 出现-1
第二种方式能够体现 "资源共享"
*
* 程序出现:
* 1)一个张票可能被卖多次(出现同票)
* 线程的执行具有随机性(原子性操作:最简单,最基本的操作语句:--,++...)
* 2)出现了负票
* 线程的延迟性导致(加入睡眠100毫秒)
* 现在的程序存在 "多线程安全问题"
public class SellTicketDemo {
public static void main(String[] args) {
//创建资源共享类对象
SellTicket st = new SellTicket() ;
//创建多个线程类对象,将资源共享类作为参数传递
Thread t1 = new Thread(st,"窗口1") ;
Thread t2 = new Thread(st,"窗口2") ;
Thread t3 = new Thread(st,"窗口3") ;
//启动线程
t1.start();
t2.start();
t3.start();
}
}
现在的程序虽然能够体现"资源共享",程序出负票和同票,如何解决安全问题?
*
* 校验多线程安全问题的标准是什么?
*
* 1)查看当前程序是否是多线程环境 是
* 2)是否存在共享数据 是 tickets
* 3)是否有多条语句对共享数据进行操作 存在
*
*
* 1),2)都必须具备:现在使用的就是多线程环境,而且存在共享数据
*
*
* 从3)入手
* Java提供一个同步机制:将多条语句对共享数据操作的使用同步代码块包括起来
* 格式:
* synchronized(锁对象){ //多个线程必须使用的同一把锁 (可以任意的Java类对象)
* 将多条语句对共享数据操作
* }
共享资源类
*
* synchronized:关键字---- 内置语言实现的(jvm来实现锁定操作: 锁的释放:自动释放)
* 可以是通过代码块(代码中),可以在方法上使用(同步方法)
* synchronized同步锁---属于"悲观锁"
* 悲观锁:自己线程本身在执行的时候,其他线程不能进入同步代码块中,其他线程不能进入
* 修改数据,保证数据的安全性! (针对频繁的写入操作)
public class SellTicket implements Runnable {
public static int tickets = 100 ;//100张票
private Demo demo = new Demo();
// private Object obj = new Object() ;
//t1,t2,t3
@Override
public void run() {
//为了模拟一直有票
while(true){
//t1,t2,t3
//加入同步代码块
//把它理解为:门的开/关
// synchronized(new Object()){ //三个线程有自己的锁对象
//t1进来,t2和t3没有办法进入的
// synchronized(obj){ //一个锁对象
//锁对象可以是任意的Java类对象
synchronized(demo){ //一个锁对象
if(tickets>0){ //t1进来
//睡眠100毫秒
//为了模拟网络延迟
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
"正在第"+(tickets--)+"张票");
}
}
}
}
}
//自定义的类
class Demo{
}
public class SellTicket implements Runnable {
//100张票
public static int tickets = 100 ;
//声明一个锁:Lock
private Lock lock = new ReentrantLock() ;
@Override
public void run() {
//模拟一直有票
while(true){
//获取一个锁:某个线程执行到这块:必须持有锁
lock.lock();
//执行完毕,手动释放锁
//在开发中 :try...catch...finally :捕获异常 ,不会使用throws
//变形格式:try...catch...catch...
//try...finally...
try{
if(tickets >0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickets--)+"张票");
}
}finally {
//释放资源代码块
//释放锁
lock.unlock();
}
1.1什么是锁?
在计算机科学中,锁(lock)或互斥(mutex)是一种同步机制,用于在有许多执行线程的环境中强制对资源的访问限制。锁旨在强制实施互斥排他、并发控制策略。
锁通常需要硬件支持才能有效实施。这种支持通常采取一个或多个原子指令的形式,如"test-and-set", "fetch-and-add" or "compare-and-swap"”。这些指令允许单个进程测试锁是否空闲,如果空闲,则通过单个原子操作获取锁。
1.2.锁的一个重要属性 粒度 Granularity [grænjʊ‘lærɪtɪ]
在引入锁粒度之前,需要了解关于锁的三个概念:
1、锁开销 lock overhead 锁占用内存空间、 cpu初始化和销毁锁、获取和释放锁的时间。程序使用的锁越多,相应的锁开销越大
2、锁竞争 lock contention 一个进程或线程试图获取另一个进程或线程持有的锁,就会发生锁竞争。锁粒度越小,发生锁竞争的可能性就越小
3、死锁 deadlock 至少两个任务中的每一个都等待另一个任务持有的锁的情况锁粒度是衡量锁保护的数据量大小,通常选择粗粒度的锁(锁的数量少,每个锁保护大量的数据),在当单进程访问受保护的数据时锁开销小,但是当多个进程同时访问时性能很差。因为增大了锁的竞争。相反,使用细粒度的锁(锁数量多,每个锁保护少量的数据)增加了锁的开销但是减少了锁竞争。例如数据库中,锁的粒度有表锁、页锁、行锁、字段锁、字段的一部分锁
相关术语 Critical Section(临界区)、 Mutex/mutual exclusion(互斥体)、 Semaphore/binary semaphore(信号量)
2.锁的种类
2.1.独享锁/共享锁
独享锁是指该锁一次只能被一个线程所持有。 (ReentrantLock、 Synchronized)
共享锁是指该锁可被多个线程所持有。 (ReadWriteLock)
互斥锁/读写锁
独享锁/共享锁这是广义上的说法,互斥锁/读写锁就分别对应具体的实现。在Java中如ReentrantLock就是互斥锁(独享锁), ReadWriteLock就是读写锁(共享锁)。 独享锁与共享锁也是通过AQS来实现的
锁升级:读锁到写锁 (不支持)
锁降级:写锁到读锁 (支持)
2.2.读写锁 ReentrantReadWriteLock
低16位代表写锁,高16位代表读锁
————————————————
版权声明:本文为CSDN博主「blackbeilei」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010648018/article/details/79750608
公平锁/非公平锁
公平锁是指多个线程按照申请锁的顺序来获取锁。
非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能会造成饥饿现象。
对于Java ReentrantLock而言,通过构造函数指定该锁是否是公平锁,默认是非公平锁。非公平锁的优点在于吞吐量比公平锁大。
对于Synchronized而言,也是一种非公平锁。由于其并不像ReentrantLock是通过AQS的控制线程对锁的获取, 所以并没有任何办法使其变成公平锁。
————————————————
版权声明:本文为CSDN博主「blackbeilei」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010648018/article/details/79750608可重入锁
可重入锁又名递归锁,是指同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取.
如上面的代码,如果synchronized不是可重入锁的话,testB就不会被当前线程执行,从而形成死锁。
需要注意的是,可重入锁加锁和解锁的次数要相等。
C==0表明未获得锁,Else表示已经获得锁,这时对state加1,相应的,每次释放锁都会对state减1
2.4.乐观锁/悲观锁
乐观锁/悲观锁不是指具体类型的锁,而是看待并发的角度。
悲观锁认为存在很多并发更新操作,采取加锁操作,如果不加锁一定会有问题
乐观锁认为不存在很多的并发更新操作,不需要加锁。数据库中乐观锁的实现一般采用版本号,Java中可使用CAS实现乐观锁。
2.5.分段锁
分段锁是一种锁的设计,并不是一种具体的锁。对于ConcuttentHashMap就是通过分段锁实现高效的并发操作。
————————————————
版权声明:本文为CSDN博主「blackbeilei」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010648018/article/details/79750608自旋锁
自旋锁是指尝试获取锁的线程不会阻塞,而是采用循环的方式尝试获取锁。好处是减少上下文切换,缺点是一直占用CPU资源。
.偏向锁/轻量级锁/重量级锁
这是jdk1.6中对Synchronized锁做的优化,首先了解下对象头(Mark Word):
运行时JVM内存布局
原文链接:https://blog.csdn.net/u010648018/article/details/79750608
* 虽然syncrhonized可以解决线程安全问题:同步代码块/同步方法,但是执行效率低,可能出现死锁
* 两个线程或者多个线程出现互相等待的情况!
解决死锁问题方案:"生产者消费者思想" 必须保证多个多线程必须使用的同一个资源对象!
public class DieLockDemo {
public static void main(String[] args) {
//创建资源类对象
DieLock dl1 = new DieLock(true) ;
DieLock dl2 = new DieLock(false) ;
//创建线程类对象
Thread t1 = new Thread(dl1) ;
Thread t2 = new Thread(dl2) ;
//启动线程
t1.start();
t2.start();
/**
* if(flag){
* synchronized (MyDieLock.objA){
* System.out.println("if objA");
* synchronized (MyDieLock.objB){
* System.out.println("if objB"); //需要等待第二个线程 objB释放锁掉
* }
* }
* }else{
* synchronized (MyDieLock.objB){
* System.out.println("else objB");
* synchronized (MyDieLock.objA){
* System.out.println("else objA");//需要等待第一个线程 将objA锁释放掉
* }
* }
* }
*
*
* 情况1:
* if objA
* else objB
*
* 当第一个ObjA锁被使用,输出"if objA"
* 同时第二个线程dl2: ObjB锁被使用 "else objB"
*
*
* 情况2:
* else objB
* if objA
*
*
* 情况3:理想情况:
* if objA
* if objB
* else objB
* else objA
*/
}
}
public class MyDieLock {
//创建两把锁对象 (静态实例变量)
public static final Object objA = new Object() ;
public static final Object objB = new Object() ;
}
测试类
* SetThread:生产数据
* GetThread:消费数据
* Student:学生数据
*
*
* 问题1 :出现数据 null--0 :
*
* 在生产资源类和消费者资源类中:分别new Student() :不是同一个对象
*
*
*
* 模拟一直有数据:加入循环操作while(true)
*
* 问题2:姓名和年龄不符
* 线程的执行具有随机性导致,多线程程序不安全
*
*
* 校验多线程安全问题的标准是什么?
* 1)查看是否是多线程环境
* 2)是否存在共享数据
* 3)是否有多条语句对共享数据进行操作
*
*
* 3)改进:使用同步代码块包括起来!
*
*
*
* 问题3:学生数据输出的时候,一次性打印很多
* 线程的一点点时间片:足够当前线程执行很多次!
*
* 优化:
* 不需要输出学生数据的时候, 一次性输出很多,而是分别依次输出
* "高圆圆" 41
* "杨德财" 27
public class ThreadDemo {
public static void main(String[] args) {
Student s = new Student() ; //同一个资源类对象
//创建生产资源类对象
SetThread st = new SetThread(s) ;
//创建消费者资源类对象
GetThread gt = new GetThread(s) ;
// 创建线程类对象
Thread sThread = new Thread(st) ;
Thread gThread = new Thread(gt) ;
//启动
sThread.start();
gThread.start();
}
}
@Version 1.0
* 生产者资源类
*/
public class SetThread implements Runnable {
private Student s ;
public SetThread(Student s){
this.s = s ;
}
//统计变量
int x = 0 ;
@Override
public void run() {
//不断产生数据
while(true){
synchronized (s){
//判断如果当生产者有数据
if(s.flag){
try {
//生产者有数据,需要等待消费者线程使用
s.wait(); //锁对象在调用wait()
//wait():当前锁对象该调用方法的时候,会立即是否锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//当前在执行下面代码的之前:线程的执行资格被GetThread所在的消费者线程
if(x % 2 == 0){
s.name = "高圆圆" ;
s.age = 41 ;
}else{
s.name = "杨德财" ;
s.age = 27 ;
}
x ++ ;
//更改标记
s.flag = true ;
//通知对方线程:赶紧使用数据
s.notify(); //锁对象调用的唤醒方法
}
}
// Student s = new Student();
}
}
消费者资源类
public class GetThread implements Runnable {
private Student s ;
public GetThread(Student s){
this.s = s ;
}
@Override
public void run() {
//模拟一直消费数据
while(true){
synchronized (s){
if(!s.flag){
//如果消费者没有数据了,需要等待生产线程产生数据
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(s.name+"---"+s.age);
//更改标记
s.flag = false ;//没有数据了
//通知对方线程:生产线程 :产生数据
s.notify() ;
}
}
// Student s = new Student() ;
}
}
public class Student {
String name ;
int age ;
//是否存在学生数据标记
boolean flag ; //true有数据,false没有数据
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
1.创建多线程的方式有几种
三种
1)继承关系:
自定一个类继承自Thread类
重写Thread类的run方法
在main中创建当前类对象,启动线程调用start()
2)实现Runnable接口
自定义一个类 实现Runnable接口
重写Runnable接口的run方法
在main中将自定义的类作为资源共享类---创建当前类对象
创建线程类Thread类对象,将资源共享类作为参数传递
分别启动线程调用start()
3)线程池
2.获取一个类的字节码文件有几种方式?
三种
1)Object类的getClass()方法
2)任意Java类型的class属性
3)反射:Class.forName("包名.类名") ;
3.wait方法和sleep方法的区别(经常会的)
1)是否释放锁
当锁对象调用wait方法,立即释放锁;
而sleep(xx):被调用的时候,线程一直处于阻塞状态,不会释放锁
2)来源不同
wait()来源于Object类----- >跟锁对象关系!
为什么将wait():线程等待 ;notify() notifyAll() 线程唤醒,定义Object类中?
因为这些方法和锁有关系,而锁对象可以是任意Java对象!
sleep():来源于Thread类---->只是属于一种状态,跟锁无关
3)他们都会抛出interruptedException:当前状态被中断,都会抛出异常!
4.线程的状态有几种?
6中
Thread类枚举类State
NEW
RUNNABLE
BLOCKED
WAITTING
TIMED_WAITTING
TERMINATED
5.什么是静态代理?请描述
静态代理:就是代理类和真实角色都需要实现同一个接口
代理类:帮助真实角色完成业务功能的增强
真实角色:专注于自己的事情
//代理角色
Thread类 implements Runnable{
private Runnable target ;
public void run(){
if(target!=null){
target .run() ;
}
}
}
//真实角色
MyRunnable implements Runnable{
//业务逻辑:完成多个线程在互相并发执行过程中抢占CPU执行权(数据)
public void run(){
...
}
}
6.如何解决线程安全问题?
同步机制:悲观锁(synchronized)
使用同步代码解决线程安全问题: 加了同步锁,其他线程不能更改它数据(针对频繁写入操作)
synchronized(锁对象){
多条语句对共享数据操作;
}
同步方法
public synchronized 返回值类型 方法名(形参列表){ //锁对象:this
...
}
Mybatis框架---->Mybatis-Plus (插件可以使用乐观锁)
7.什么是Java中的等待唤醒机制?
等待唤醒机制---称为"等待通知",习惯于叫等待唤醒
当前多个线程出现循环等待-----死锁
使用notify() notifyAll() 将阻塞状态中线程进行唤醒,来操作业务数据!
多个线程必须使用的是同一个资源对象!
创建型设计模式:对象的创建
* Java提供:简单工厂模式 ---静态工厂方法模式
* 优点:不需要具体类创建具体实例,通过工厂类创建
*
* 弊端:一旦有一个新的类型增,修改工厂类!
*
* 需要提供一个工厂类,负责具体的实例的创建
public class Test {
public static void main(String[] args) {
//创建猫
Cat cat = new Cat() ;
cat.eat();
cat.sleep();
//狗
Dog dog = new Dog() ;
dog.eat();
dog.sleep();
System.out.println("------------------------");
//提供工厂类创建具体的动物实例
/* Cat c1 = AnimalFactory.createCat();
c1.eat();
c1.sleep();
Dog d = AnimalFactory.createDog() ;
d.eat();
d.sleep();*/
//优化之后
Animal animal = AnimalFactory.createAnimal("dog"); //父类引用指向子类对象
animal.eat();
animal.sleep();
animal = AnimalFactory.createAnimal("cat") ;
animal.eat();
animal.sleep();
}
}
public class Animal {
public void eat(){
System.out.println("动物都需要吃");
}
public void sleep(){
System.out.println("动物都需要休息");
}
}
public class AnimalFactory {
//构造方法私有化
private AnimalFactory(){ //外界不能创建当前类对象
}
//静态方法
//创建猫的实例
/* public static Cat createCat(){
return new Cat() ;
}
//创建狗的实例
public static Dog createDog(){
return new Dog() ;
}
//创建猪的实例
public static Pig createPig(){
return new Pig() ;
}*/
//优化:利用多态:提供功能扩展
public static Animal createAnimal(String type){
if(type.equals("dog")){
return new Dog() ;
}else if(type.equals("cat")){
return new Cat() ;
}else if(type.equals("pig")){
return new Pig() ;
}else{
System.out.println("对不起,工厂类没有提供者动物的实例创建!");
}
return null ;
}
}
public class Cat extends Animal {
public void eat(){
System.out.println("i can eat and eat mouse");
}
public void sleep(){
System.out.println("i can sleep ...");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("i can eat and eat meat");
}
public void sleep() {
System.out.println("i can sleep");
}
}
工厂方法模式:
*
* 对象创建的工作:有一个接口完成
* 接口的子实现类---->创建具体实例的工厂类
*
* 优点:面向接口编程: 结构非常清晰,维护起来容易
*
* 弊端:代码量增加了,需要编写额外的工厂类...
public class Test {
public static void main(String[] args) {
//没有使用工厂方法模式
//抽象类多态
Animal a = new Cat();
a.eat();
a = new Dog() ;
a.eat();
System.out.println("-----------------------------------");
//猫的工厂类
Factory f = new CatFactory() ;
Animal animal = f.createAnimal(); //new Cat()
animal.eat();
f = new DogFactoy() ;
Animal an = f.createAnimal();
an.eat();
}
}
public interface Factory { //工厂接口
//创建动物的实例
public abstract Animal createAnimal() ;
}
public class DogFactoy implements Factory {
@Override
public Animal createAnimal() {
return new Dog();
}
}
public abstract class Animal {
public abstract void eat() ;//吃
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
创建型设计模式之单例
*
* 单例:
* 在加载某个类的时候,内存中始终只有一个对象!(该类对象自动创建)
*
* 两种:
* 饿汉式:特点 永远不会出现问题的单例模式!
* 在加载这个类的时候,就已经在内存中创建了一个对象!
* 1)自定义一个类(具体类)
* 2)成员位置:创建当前类的实例
* 3)提供私有的构造方法:外界不能够创建它
* 4)对外提供公共的访问方法:静态的,返回值当前类本身
*
* 懒汉式:可能出现问题的单例模式
* 1)自定义一个类(具体类)
* 2)成员位置:声明类型的变量
* 3)构造方法私有化
* 4)提供对外的公共访问方法:
* 需要判断:当前如果没有对象,new 对象
*
* 存在懒加载或者延迟加载!
* 可能出现多线程 安全问题:
*
* 如何解决
* 加同步锁
public class Tests {
public static void main(String[] args) {
/*Student s =new Student() ;
Student s2 = new Student() ;
System.out.println(s==s2) ;//false
System.out.println(s.getClass()==s2.getClass());//true*/
//getClass()---->class 包名.类名
// Student.s = null ; //被外界更改掉
Student s1 = Student.getStudent();
Student s2 = Student.getStudent();
System.out.println(s1==s2);
System.out.println("-----------------");
Programmer p1 = Programmer.getPro();
Programmer p2 = Programmer.getPro();
Programmer p3 = Programmer.getPro();
System.out.println(p1==p2);
System.out.println(p1==p3);
}
}
* 标准单例模式之饿汉式:Runtime
* 个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接
*/
public class RuntTimeDemo {
public static void main(String[] args) throws IOException {
Runtime runtime = Runtime.getRuntime();
// Runtime runtime2 = Runtime.getRuntime();
//System.out.println(runtime==runtime2);
int cpuSize = runtime.availableProcessors();
System.out.println(cpuSize);
runtime.exec("notepad") ;
runtime.exec("mspaint") ;
runtime.exec("calc") ;
}
}
public class Student {
//创建该类实例---(类的实例变量)
// public static Student s = new Student() ;
private static Student s = new Student() ;
private Student(){} //外界不能创建对象
//提供对外的公共访问方法:静态的
public static Student getStudent(){
return s ;
}
}
public class Programmer {
private static Programmer pro = null ;
private Programmer(){}
//p1,p2,p3
//对外公共访问方法
/*public static Programmer getPro(){
synchronized (Programmer.class){
if(pro ==null){
pro = new Programmer() ;
}
return pro ;
}
}*/
public synchronized static Programmer getPro(){//静态同步方法:锁对象:当前类名.class属性
if(pro ==null){
pro = new Programmer() ;
}
return pro ;
}
}
龟兔赛跑
*
*
* 跑道---作为资源类
public class Race implements Runnable{
//当类一加载的时候,定义静态变量
//胜利者
private static String winner = null ;
//兔子和乌龟都要执行这个run
@Override
public void run() {
//for循环:表示步数1-100步
for(int x = 1 ; x <= 100 ; x ++){
//真实故事中:兔子要睡觉的,模拟兔子睡觉
if(Thread.currentThread().getName().equals("兔子") && (x % 10 ==0 )){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//定义一个定义比赛结束的方法
boolean flag = gameOver(x) ;
if(flag){
break ;
}
System.out.println(Thread.currentThread().getName()+"跑了====>"+x+"步");
}
}
//比赛结束的方法
private boolean gameOver(int step) {//步数 x
//情况1:如果当前winner不等于null,存在胜利者,比赛结束
if(winner!=null){
return true ;
}{
//情况2: 判断如果当前step>=100 比赛也要结束
if(step>=100){
winner = Thread.currentThread().getName() ;
System.out.println("winner is:"+winner);
return true ;
}
}
return false ;
}
//用户线程
public static void main(String[] args) {
//创建一个资源共享类
Race race = new Race() ;
//创建线程类对象
Thread t1 = new Thread(race,"兔子") ;
Thread t2 = new Thread(race,"乌龟") ;
t1.start();
t2.start();
}
}
线程组 ThreadGroup 线程组表示一个线程的集合
*
* Thread类中方法:
* public final ThreadGroup getThreadGroup():获取当前所有线程的默认线程组
* ThreadGroup
* public final String getName() :获取默认的线程组名称: (默认就是main)
*
*
* 构造方法:
* ThreadGroup(String name):构造一个新的名称的线程组
*
* 所有的线程默认的线程组就是main线程(用户线程)
public class ThreadGroupDemo {
public static void main(String[] args) {
//method() ;
method2() ;
}
//设置线程组名称
private static void method2() {
// ThreadGroup(String name):构造一个新的名称的线程组
ThreadGroup tg = new ThreadGroup("myMain") ;
//创建线程类对象:可以将线程组对象作为参数传递
//public Thread(ThreadGroup group,String name)
Thread t1 = new Thread(tg,"线程1") ;
Thread t2 = new Thread(tg,"线程2") ;
System.out.println(t1.getThreadGroup().getName());
System.out.println(t2.getThreadGroup().getName());
}
private static void method() {
//创建两个线程类对象
MyThread my1 = new MyThread() ;
MyThread my2 = new MyThread() ;
//获取对应的线程组名称
ThreadGroup tg1 = my1.getThreadGroup();
String name = tg1.getName();
ThreadGroup tg2 = my2.getThreadGroup();
String name2 = tg2.getName();
System.out.println(name);
System.out.println(name2);
}
}
线程池的使用:
* 1)接口:ExecutorService :跟踪一个或者多个异步任务
* 2)如何实例化---->Executors.newFixedThreadPool(int) 工厂方法:
*
* Executors:工厂类
* 提供创建线程池对象的方法
* public static ExecutorService newFixedThreadPool(int nThreads)
*
* ExecutorService
* 方法:
* Future<?> submit(Runnable task) :通过线程池提交异步任务
* <T> Future<T> submit(Callable<T> task):提交异步任务
*
* Future:异步任务计算的结果!
*
*
* 第三种方式:线程池实现---->还是自定义一个类 实现Runnable接口
public class ThreadDemo {
public static void main(String[] args) {
/* new Thread(){
@Override
public void run() {
}
}.start();*/
//创建一个线程池:静态工厂模式
ExecutorService pool = Executors.newFixedThreadPool(2);
//提交异步任务
// Future<?> submit(Runnable task) :通过线程池提交异步任务
/* pool.submit(new MyRunnable()) ;
pool.submit(new MyRunnable()) ;*/
//Callable要比Runnable接口更好
//可以跟踪具体的异常错误(如果执行过程中,线程出现异常,可以跟踪异常信息!)
pool.submit(new MyCallable()) ;
pool.submit(new MyCallable()) ;
//使用完毕,关闭线程池--将底层产生的线程归还线程池中
pool.shutdown();
}
}
j ava.util.Timer:定时器 :有线程安排执行务执行一次,或者定期重复执行。
* 构造方法:
* public Timer() 无参构造方法
*
* 成员方法
* public void cancel():取消定时器
* public void schedule(TimerTask task,Date time) :在指定日期时间内执行这个任务
* public void schedule(TimerTask task,long delay):在指定的延迟时间后执行task任务(时间:毫秒)
*
* public void schedule(TimerTask task,
* long delay,
* long period) :在指定的delay延迟时间后开始重复时间间隔period来执行task任务
*
* 需求:
* 在某天的18点将 d://demo文件夹 中的所有的带后缀为.java文件删除掉! (Timer+io流+递归:综合使用)
*
*
*
* Java设计原则:
* 单一职责
* 接口分离
* 开闭原则
* 依赖注入原则(依赖于抽象类或者接口,而不依赖具体类实现)
public class TimerDemo {
public static void main(String[] args) {
//创建一个定时器
Timer timer = new Timer() ;
// public void cancel():取消定时器
//参数1:定时任务:抽象类,定义子类继承自TimerTask
// timer.schedule(new MyTask(timer),3000); :3秒后执行一次这个任务
/* public void schedule(TimerTask task,
long delay,
long period) :在指定的delay延迟时间后开始重复时间间隔period来执行task任务*/
timer.schedule(new MyTask(timer),2000,3000);
}
}
//定时任务
class MyTask extends TimerTask{ //TimerTask实现Runnable接口 ---会使用同步机制
private Timer t ;
public MyTask(Timer t){
this.t = t ;
}
@Override
public void run() {
System.out.println("bom...");
//关闭定时器
//t.cancel() ;
}
}
1.多线程创建方式有几种,列举
1)继承自Thread类 重写run方法,然后创建当前类对象 启动线程
2)实现Runnable接口 重写run方法,然后将当前资源类作为参数传递 到Thread类中 然后启动线程
new Thread(new Runnable(){
public void run(){
...
}
}).start ;
3)线程池
工厂类:Executors
public static ExecutorService newFixedThreadPool(int nThreads)
通过它的子实现对象:ThreadPoolExecutor
7个参数:
corePoolSize
maxmiumPoolSize
handler:自动启用拒绝策略
TimeUnit:计时器
ThreadFactory---创建新的线程对象
DefaultThreadFactory
keepAliveTime:保存存活时间
BlockingQueue queue 阻塞队列(Collection)
ExecutorService
Future submit(Callable<E> call) :提交异步任务
2.什么是单例模式,请列举两种情况
创建对象时候,始终保证内存只有一个对象!
单例模式:
饿汉式:不会出现安全的单例模式 :Runtime
当前类一加载的时候,就立即创建一个对象(只有这一个对象)
1)当前类是一个具体类
2)类的成员位置:创建的当前静态实例变量并且私有化
3)无参构造方法私有化
4)提供对外的公共访问方法:静态方法,并且返回值是当前类本身
public class Student{
private static Student s = new Student() ;
private Student(){}
public static Student getStudent(){
return s ;
}
}
懒汉式:可能出现安全问题的单例模式 (实际开发中:懒加载 / 延迟加载!)
1)当前类是一个具体类
2)不会立即创建一个当前类对象:而是声明当类型的成员变量
3)无参构造方法私有化
4)提供对外的静态的公共访问方法:返回值也是当前类本身
先判断当前是否存在类对象,如果为null,新创建一个对象
返回当前类对象;
class Teacher{
private static Teacher t = null ;
private Teacher(){}
//t对象被共用
//并发的线程 访问公共变量:就会出现冲突
//使用同步机制:synchronized
public synchronized static Teacher getTeacher(){
if(t==null){ //需要使用的时候,才创建对象!
t = new Teacher() ; //新建一个对象
}
return t ;
}
}
Teacher t1 = Teacher.getTeacher() ;
Teacher t2 = Teacher.getTeacher() ;
3.什么是简单工厂以及工厂方法模式
简单工厂:静态工厂方法模式
优点:不需要具体类 new 具体类,而是需要通过工厂类
工厂类的职责:就是负责具体类的对象的创建!
弊端:
当有新的类型增加,需要频繁的修改工厂类代码! (可以使用多态!)
工厂方法:
需要有工厂接口,工厂接口中的方法 返回值某个抽象类型
抽象类还需要有具体的子类,而具体类对象的创建工作:由工厂接口的 的子实现类(具体类的工厂类)
interface Factory{
public abstract Animal createAnimal() ;
}
//狗的工厂类
class DogFactory implements Factory(){
public Animal createAnimal(){
return new Dog() ;
}
}
优点:面向接口编程而且使用接口多态,提供功能扩展性
弊端:代码量大:一个新的类型增加,需要提供工厂类
4.集合和数组的区别
长度区别
集合:可变
数组:固定
存储元素
集合:可以存储任意类型的元素 :引用类型
数组:既可以存储引用类型,也可以存储基本类型 (元素类型必须统一)
存储的数据类型区别
数组:数据类型:必须统一
集合:只能引用类型
5.多线程的同步机制是什么
解决:
并发线程中针对公共变量访问冲突变量
同步机制:四种
1)ThreadLocal -----> 数据库连接池会使用! (创建Connection:连接对象)
2)同步代码块/同步方法 synchronized
3)wait()或者 notify()
4)volatile
MES系统
URL是URI的子集
URI
/dianshang/login
URI指定的具体的访问的路径:
协议
ftp协议
迅雷协议
邮件协议
jdbc:
http协议
URL:
网络协议: http/ https:加密协议 更安全
http://www.baidu.com:80/index.html
http://localhost:8080/dianshang/login
*