文章目录
集合应用-----------斗地主洗牌发牌
分析: 用HashMap<Integer,String>集合作为牌盒,key键存储牌的编号,value值存储牌
用ArrayList集合存储牌的编号,用作后面的发牌
定义String[] 存储牌的点数{“3”,“4”,“5”,“6”…“A”,“2”};
定义String[] 存储牌的花色{“♠”,“♥”,“♣”,“♦”};
定义int index=0,用作编号的存储
通过增强for循环嵌套,完成装除了大小王牌的操作,同时ArrayList集合中装入对应的编号
再添加大小王和对应的编号
//洗牌
利用Collections集合工具类中的public static void shuffle(List<?> list)随机置换ArrayList中牌的编码
创建四个TreeSet集合,分别代表玩家1,玩家2,玩家3,底牌
利用for循环语句将牌分别发给上面四个
编写看牌方法,将玩家的牌和底牌打印出来
代码如下:
package poker2;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.TreeSet;
import javax.swing.LookAndFeel;
public class Poker {
public static void main(String[] args) {
// TODO Auto-generated method stub
//牌盒 k存储编号 v存储牌
HashMap<Integer,String> hm=new HashMap<Integer,String>();
//存储编号
ArrayList<Integer> array=new ArrayList<Integer>();
//点数和花色数组
String[] num= {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
String[] colors= {"♠","♥","♣","♦"};
int index=0;
//装牌,装编号
for (String n : num) {
for (String c : colors) {
String str=c.concat(n);
hm.put(index, str);
array.add(index);
index++;
}
}
hm.put(52, "小王");
hm.put(53, "大王");
array.add(52);
array.add(53);
//洗牌
Collections.shuffle(array);
//发牌
TreeSet<Integer> player1=new TreeSet<Integer>();
TreeSet<Integer> player2=new TreeSet<Integer>();
TreeSet<Integer> player3=new TreeSet<Integer>();
TreeSet<Integer> dipai=new TreeSet<Integer>();
for(int i=0;i<array.size();i++) {
if(i>=array.size()-3) {
dipai.add(array.get(i));
}else if(i%3==0){
player1.add(array.get(i));
}else if(i%3==1){
player2.add(array.get(i));
}else if(i%3==2){
player3.add(array.get(i));
}
}
look("张三", player1, hm);
look("李四", player2, hm);
look("王五", player3, hm);
look("底牌", dipai, hm);
}
public static void look(String name,TreeSet<Integer> ts,HashMap<Integer,String> hs) {
System.out.print(name+"的牌是: ");
for (Integer i : ts) {
System.out.print(hs.get(i)+" ");
}
System.out.println();
}
}
异常
* 什么是异常
* 程序出现了问题,使用"异常"来描述问题
* 举例:
* 生活中一些问题
*
* 班长骑车去旅行
* 1)在骑行的过程中,路面塌陷了,导致不能骑行了!----- 不可抗力的因素!(严重问题)
* 2)在准备骑行的时候,车胎没气了,导致不能骑行了!----
* 在骑行前应该检查的工作(可以检查维修,可以解决的)
* 3)在骑行过程中,中间路面是平坦的,两边是石子,就在两边上骑行,导致车胎没气了
* -----
* 在骑行的时候,no zuo no die (自己的原因导致)
*
* java.lang.Throwable:异常类( Java 语言中所有错误或异常的超类(父类))
* error:严重错误(严重问题)
* 比如:内存异常!OOM(Out Of Memory)
* 通过加入内存条...或者将Linux虚拟机的内存空间设置小一点!
*
* Exception: 可以捕获合理的程序!
* 编译时期异常:只要不是RuntimeException中的子类都是属于编译时期
* 必须要处理的,不处理编译通不了,没有办法运行的!
* 运行时期异常RuntimeException:
* 程序在执行过程中出现的问题
* 代码逻辑不够严谨导致的!
异常处理的方法
* 异常的处理方案有哪些:
*
* 1)try...catch...finally:标准格式 捕获异常
* 2)throws:抛出异常 (抛出到方法上)
*
* 方式1:捕获异常的变形格式
* try...catch...
* try...catch...catch...
* try...finally... (线程中:Lock锁)
*
* 格式:流程
* try{
* ...
* ...
* 可能出现问题代码
* }catch(异常类名 变量名){//具体异常的类
* //处理异常
* //自己手动处理
* //Throwable类中一些方:处理方式(jvm将异常信息输出在控制台并且可以跟踪异常类源码)
* }
多个异常的处理
* 如果try中存在多个异常,如何处理
* 1)一个一个try...catch...
* 2)一个try多个catch...
* try...catch...finally(标准格式)
* 变形格式:
* try...catch...
* try...catch...catch...(推荐)
编译时期异常,运行时期异常
* 编译时期异常和运行时期的区别?
*
* 编译时期的异常:
* 举例:
* String---Date---解析的方法parse(String source) throws ParseException{}
*
* IO流:IOException
* ...
* 开发者必须要进行显示处理,否则编译通过不了!
*
* 运行时期异常:
* 1)代码逻辑的问题,不进行显示处理,在代码中加入一些逻辑判断
* 2)也可以进行显示处理:try...catch...
Throwable中的一些方法
* 关于Throwable中的一些方法
*
* public String getMessage():获取异常的消息字符串
*
* public String toString():获取异常信息的简单描述
* 异常的全限定名称:包名.类名: 调用该异常对象的getMessage()详细的消息字符串
*
* public void printStackTrace():
* 将此对象的信息追踪到堆栈中,具体获取到具体源码中哪一块出问题了
Throws和Throw的区别
* 针对异常处理的另一种方式:
*
* throws:抛出异常
* 抛出在方法声明上,如果方法中的语句体出现了异常,将异常交给jvm,jvm将异常信息输出
* 控制台上...
*
*
* 面试题
* throws和throw的区别
*
* throws:抛出
* 1)书写位置是在方法声明上
* 2)throws的后面跟的异常类名,而且可以跟多个异常类名,中间使用逗号隔开
* 3)对于throws它是由调用者进行处理,必须要对带throws的方法进行处理!
* 4)throws表示抛出异常的一种肯能性(这个方法可能出现问题/可能没有问题!)
* throw:抛出
* 1)书写位置是在方法体中
* 2)throw的后面跟的异常对象,一般都是匿名对象 new XXXException()
* 而且只能跟一个异常对象
* 3)由方法中逻辑判断进行处理(由方法体中语句进行处理)
* 4)throw:表示抛出异常一种肯定性(执行到逻辑的时候,一定会执行这个异常!)
异常的注意事项
-
异常的注意事项:
-
1)子类继承父类的时候,对父类的成员方法进行重写,如果父类的成员方法有异常
-
那么子类的该方法针对异常处理,要么是跟父类的异常类名一致,要么是父类异常类的子类
-
2)子类继承父类重写父类的方法的时候
-
父类的成员方法没有抛出异常,子类的该方法不能抛出异常,只能try…catch…
异常捕获的标准格式
* 捕获的标准格式 * try{ * //可能出现问题的代码 * }catch(异常类名 对象名){ * 对象名.printStackTrice() ; * }finally{ * //释放相关系统资源close() * //举例:IO流中: createNewfile():创建文件的方法 * //举例:JDBC:java 连接数据库 * //Connection: 连接对象---- 使用完毕需要关闭相关的系统资源! * //Statement:执行对象(增删查改的操作):---使用完了也需要释放系统资源 * } * * try中代码如果不存在问题,代码正常执行,需要执行finally语句,释放系统资源! * finally特点: * 释放相关的系统资源,而且finally中的代码一定会执行的;除非在执行finally语句之前 * JVM退出了! System.exit(0) ;
面试题
* 面试题 * 如果捕获异常的时候, * try...catch...finally,catch中如果有return语句,那么finally中的代码还会执行吗? * 在return之前执行还是return之后执行 * 会执行,除非Jvm退出了不执行! * return 之前 * */ public class FinallyDemo2 { public static void main(String[] args) { System.out.println(getNum(10)); } private static int getNum(int a) { System.out.println(a); //10 //重新给a赋值 try { a = 20 ; //a =20 System.out.println(a/0);//除数为0的异常 } catch (Exception e){//执行catch语句: 捕获具体的异常 a = 30 ; //a = 30 return a ; //return 30 :已经形式返回路径! ,如果catch中有return语句,finally代码一定会执行, //在catch之前执行! }finally { a = 40 ; //a = 40 } return a; } }
自定义异常
自定义的异常!
1)自定义一个类,继承自Exception或者RuntimeException
2)提供无参构造方法 /有参构造 传递String参数(消息字符串)
多线程
要实现多线程—线程是依赖于进程,创建进程---->创建系统资源
但是Java语言不能够直接创建系统的,JDK提供一个类:Thread
线程类
jvm是可以运行多个线程并发的执行
并发:在同一个时间点同时发生的!
方式1: 继承Thread类
1)自定义一个类 继承Thread类 :线程类
2)重写Thread类中的run方法
3)在当前用户线程中(main)中创建该类对象,
启动线程 :start()方法
方式二: 实现Runnable接口
1) 定义一个类实现Runnable接口
2) 重写Runnable 接口中的run方法
3) 创建资源类对象
4) 创建Thread类对象,将资源类对象作为形参传递
5) start方法开启线程
方式三: 线程池
- 利用工厂类Executors的静态方法,返回ExecutorService对象
public ExecutorService newFixedThreadPool(int nThread)
- 提交异步任务
线程池对象.submit(Callable call) 借用Callable接口中的 call()方法,返回值为类型的Future
或者
线程池对象.submit(Runnable r) 没有返回值
- 线程池对象.shutDown()
设置线程的名称
public final void setName(String name)
获取线程的名称
public final String getName()
启动线程为什么是start而不是run方法
1).首先启动线程之前需要给线程分配系统资源,在这一点上,用run方法只是相当于一个方法的简单调用
并没有创建系统资源给线程
2).start方法中的start(0)方法是非java语言,可以实现系统资源的分配,开启线程
3).run方法相当于一个线程的任务,start方法才是开启任务的命令
源码如下:
public synchronized void start() {
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
private native void start0();
Thread类的一些方法
获取当前线程对象
public static Thread currentThread()
获取线程名称
getName():获取线程名称
设置当前线程名称
setName(String name)
设置守护线程
public final void setDaemon(boolean on)
在启动线程之前,调用这个方法才能设置为守护线程 (注意事项!)
true则设置为守护线程
-
(如果当前运行中线程都是守护线程,JVM退出)
等待线程终止
public final void join() throws InterruptedException
等待当前线程执行完毕之后,其他线程就可以互相继续抢占
底层源码如下:
/** * Waits for this thread to die. * * <p> An invocation of this method behaves in exactly the same * way as the invocation * * <blockquote> * {@linkplain #join(long) join}{@code (0)} * </blockquote> * * @throws InterruptedException * if any thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is * cleared when this exception is thrown. */ public final void join() throws InterruptedException { join(0); //join()等同于join(0) } /** * Waits at most {@code millis} milliseconds for this thread to * die. A timeout of {@code 0} means to wait forever. * * <p> This implementation uses a loop of {@code this.wait} calls * conditioned on {@code this.isAlive}. As a thread terminates the * {@code this.notifyAll} method is invoked. It is recommended that * applications not use {@code wait}, {@code notify}, or * {@code notifyAll} on {@code Thread} instances. * * @param millis * the time to wait in milliseconds * * @throws IllegalArgumentException * if the value of {@code millis} is negative * * @throws InterruptedException * if any thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is * cleared when this exception is thrown. */ public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { while (isAlive()) { wait(0); //join(0)等同于wait(0),即wait无限时间直到被notify } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
join()依赖wait()方法,join()相当于wait(0)
线程的优先级:
-
public static final int MAX_PRIORITY:最大优先级 10
-
public static final int MIN_PRIORITY:最小优先级 1
-
public static final int NORM_PRIORITY:默认优先级 5
获取线程的优先级
public final int getPriority()
设置线程的优先级
public final void setPriority(int newPriority)
- 优先级越大的线程抢占CPU的执行权几率大
- 优先级越小的线程抢占CPU的执行几率小
- 符号线程的执行具有随机性
线程睡眠
public static void sleep(long millis) throws InterruptedException
线程睡眠 (阻塞式方法!)
- 参数为时间毫秒值!
- 线程睡眠到期自动苏醒,并返回到可运行状态,不是运行状态
线程的状态
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
中断线程 :
public void interrupt():中断线程的一种状态!(6种状态),
暂停线程
public static void yield():暂停当前正在执行的线程对象,并执行其他线程!
- yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。
多线程安全问题
检验多线程安全问题的标准是什么?
-
1)查看当前环境是否是多线程环境
-
2)当前程序中是否存在共享数据
-
3)是否有多条语句对共享数据进行操作
-
为了解决这个问题:Java提供了一个关键字:synchronized
-
同步代码块
-
synchronized(锁对象){ //门的开/关
-
多条语句对共享数据进行操作
-
锁对象:多个线程应该使用的是通一把锁!
解决方案:同步机制
关键字:
同步代码块—解决线程安全问题
锁对象:可以是任意Java类对象 Object obj = new Object();
synchronized(锁对象){
将多条语句对共享数据的操作包裹起来;
}
同步方法:非静态的 锁对象:this
方法声明上加入一个synchronized
静态的同步方法
//static是类相关:,对于静态的同步方法的锁对象是谁呢?
锁的对象是当前类名.class
代理
- 代理分类:
-
静态代理
- 动态代理
-
JDK动态代理
-
Cglib动态代理
- 静态代理
-
1)真实角色只专注于自己的事情
-
2)找一个代理类---代理角色来完成真实角色完成不了的事情
-
代理角色和真实角色都需要实现同一个接口 (Thread类:多线程的实现方式2)
-
Tread类:真实角色----启动线程(完成自己的事情):系统资源启动
-
自定义类:MyRunnable implements Runnable{} 代理角色
-
代理角色重写run方法()
-
完成代理的业务...
可重入锁Lock
- java.util.concurrent.locks.Lock
- juc包下的接口
-
Lock接口提供一些相关的功能,比synchronized有具体的锁定操作(具体的功能
- 获取锁/释放锁)
- Lock不能直接实例化:
-
具体的子实现类ReentrantLock
功能:
- public void lock():获取锁
- public void unlock():试图释放锁
等待唤醒机制
是一种多线程之间进行通信的方法,保证了多线程对共享资源操作的顺序,利用同一把锁的wait方法和notify方法,控制多个线程之间的执行顺序,典型的是在生产者消费者模式中,生产者不断的生产数据,等待消费者消费,消费者不断的消费数据,等待生产者生产
举例: 不断存入一个学生的姓名和年龄,然后不断将其打印出来
代码如下:
共享资源类 Student类
public class Student {
String name;
int age;
//true 代表创建好了学生对象 false 代表创建好的学生对象被使用了
boolean flag; //默认false
int i=0;
//同步加锁方法存入学生信息
public synchronized void setStudent() {
if(flag) {//代表有学生信息了,此时线程等待
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {//没有学生信息,需要存入
if(i%2==0) {
name="高圆圆";
age=41;
}else {
name="张冲";
age=23;
}
i++;
flag=true;//存好学生信息了,需要消费了
notify();//唤醒消费线程
}
}
//同步加锁方法,获取学生信息
public synchronized void getStudent() {
if(flag) {//有学生信息了,可以打印了
System.out.println(name+"----"+age);
flag=false;//使用完了,需要生产了
notify();//唤醒生产线程
}else {//没有学生信息,无法打印,等待生产
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
生产者类
public class SetThread extends Thread{
private Student s;
public SetThread(Student s) {
this.s=s;
}
@Override
public void run() {
while(true) {
s.setStudent();
}
}
}
消费者类
public class GetThread extends Thread {
private Student s;
public GetThread(Student s) {
this.s=s;
}
public void run() {
while(true) {
s.getStudent();
}
}
}
测试类
public class StudentDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Student s=new Student();
SetThread st=new SetThread(s);
GetThread gt=new GetThread(s);
st.start();
gt.start();
}
}