1.TreeMap
TreeSet的底层就是由TreeMap维护的,底层原理:红黑树。
特点:有序(默认升序排序),存放存储与内部真实存储顺序是不一致的;
注意:有什么功能|结构能够实现排序的,想到比较器,指定比较规则;
去重排序:根据key实现,key中存放数据的类型——>
1)实现内部比较器
2)实现外部比较器
public class PracticeDemo {
public static void main(String[] args) throws IOException {
//创建TreeMap对象
TreeMap<User,String> map = new TreeMap<>();
//增加元素
map.put(new User("aaa",15),"新浪");
map.put(new User("bbb",16),"新浪");
map.put(new User("ccc",17),"新浪");
map.put(new User("aaa",16),"新浪");
map.put(new User("abc",15),"新浪");
System.out.println(map);
System.out.println("===================");
//使用entrySet进行遍历
Set<Map.Entry<User,String>> set = map.entrySet();
Iterator<Map.Entry<User,String>> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//values遍历,打印values的值
Collection<String> col = map.values();
Iterator<String> it3 = col.iterator();
while(it3.hasNext()){
System.out.println(it3.next());
}
}
class User implements Comparable<User>{
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return age == user.age &&
Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(User o) {
return this.getName().compareTo(o.getName());
}
}
2.Properties
属于Map接口下的实现类。
存储的键值对都为字符串类型;
Properties类表示一组持久的属性;
Properties格式作为配置文件得格式存在,键值对都是字符串;
配置文件:
- 文件中指定一些程序执行过程中需要的一些数据|参数|路径;
- 帮助我们实现软编码风格(经常修改的数据与源代码分离开,避免经常修改操作源代码——>硬编码);
//properties中的内容
账户:账户1
密码:密码1
age:15
程序从properties文件中读取数据:
//properties作为配置文件
Properties pro = new Properties();
pro.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("xx.properties"));
System.out.println(pro.getProperty("账户"));
System.out.println(pro.getProperty("密码"));
System.out.println(pro.getProperty("age"));
}
总结:properties作为配置文件使用的步骤:
- src下新建一个file文件,名字问xx.properties
- zai配置文件中定义键值对为字符串的数据(注意不加"",;…)
- 程序中定义个Properties对象.通过对象.load(流) 指定从某一个资源文件中读取数据,使用指定的流
- 对象.getProperty(key)
3.Collections
CollectionsCollection的区别:
- Collection是集合体系的上层接口;
- Collections操作集合数据的工具,与Arrays很像;
常用方法:
- void sort 排序;
- void reverse 倒转;
- void binarySrearch 将排序好的集合进行二分查找;
- void shuffle 随机排序;
public class CollectionsDemo {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(2);
list.add(5);
list.add(3);
list.add(1);
System.out.println(list);
//升序排序
Collections.sort(list);
System.out.println(list);
//倒转
Collections.reverse(list);
System.out.println(list);
//乱序
Collections.shuffle(list);
System.out.println(list);
//查找,前提是必须将集合排序
Collections.sort(list);
System.out.println(Collections.binarySearch(list,2));
}
}
4.线程安全问题
- Hashtable类型,线程安全的HashMap;Hashtable是同步的。 如果不需要线程安全实现,建议使用HashMap代替Hashtable 。 如果需要线程安全的高度并发实现,则建议使用ConcurrentHashMap代替Hashtable ;
- Collections -> static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) 返回由指定映射支持的同步(线程安全)映射;
- juc包(高级并发编程包) - > ConcurrentHashMap 线程安全的哈希表—>推荐,安全性好效率高;
5.线程
单线程:单个任务,一个执行路径,一个顺序流;
多线程:多个任务执行,多个路径执行,多个顺序流,优点是效率高;
串行:在同一个时间段内,多个任务快速串行执行
并行:在同一个时刻内,多任务同时执行;
5.1创建线程和开启线程
- 继承Thread,重写run()+start():
public class ThreadDemo extends Thread{
public static void main(String[] args) throws InterruptedException {
//创建本类的对象
ThreadDemo th =new ThreadDemo();
//通过本类对象调用重写的方法
th.start();
for(int i = 0;i<=20;i++){
System.out.println("歇一歇");
Thread.sleep(100);
}
}
//重写run方法
@Override
public void run() {
for(int i = 0;i<=20;i++){
System.out.println("做俯卧撑");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
- 实现Runnable,重写run()方法,方法内部定义线程体+start();接口可以多实现,而类只能单继承,此方法也可以资源共享;
//实现Runnable接口
public class ThreadDemo02 implements Runnable{
public static void main(String[] args) throws InterruptedException {
//创建Thread对象,它的实参为本类的对象(重写run方法的对象)
new Thread(new ThreadDemo02()).start();
for(int i =0;i<=50;i++){
System.out.println("下去");
Thread.sleep(100);
}
}
//重写run方法
@Override
public void run() {
for(int i =0;i<=50;i++){
System.out.println("上去了");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
使用内部类实现此方法:
public class ThreadDemo03 {
//内部类
class Inner1 implements Runnable{
@Override
public void run() {
for(int i = 0;i<51;i++){
System.out.println(Thread.currentThread().getName()+"吃饭!!!");
}
}
}
public static void main(String[] args) {
ThreadDemo03 th = new ThreadDemo03();
//调用非静态内部类,需要使用类对象调用
new Thread(th.new Inner1(),"a").start();
new Thread(th.new Inner1(),"b").start();
//lambda表达式
new Thread(()->{
for(int i = 0;i<51;i++){
System.out.println(Thread.currentThread().getName()+"睡觉!!!");
}
},"c").start();
}
}
12306练习:
public class Web12306 implements Runnable{
int tickets = 100;
public static void main(String[] args) {
Web12306 web = new Web12306();
new Thread(web,"小张").start();
new Thread(web,"小王").start();
new Thread(web,"小李").start();
}
@Override
public void run() {
while(tickets>0){
System.out.println(Thread.currentThread().getName()+"抢到了第"+tickets--+"票");
try{
Thread.sleep(100);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
归途赛跑例子:
public class Race{
public static void main(String[] args) {
Match match = new Match();
new Thread(match,"乌龟").start();
new Thread(match,"兔子").start();
}
}
//定义一个比赛类
class Match implements Runnable{
//此成员变量作为比赛停止条件
private String name;
@Override
//重写的run方法
public void run() {
for(int i = 1;i<=100;i++){
System.out.println(Thread.currentThread().getName()+"跑了:"+i+"步");
//此if判断调用该线程的是否为兔子,如果是,则每20步停下20毫秒
if("兔子".equals(Thread.currentThread().getName()) && i%20==0){
try{
Thread.sleep(2);
}
catch (Exception e){
e.printStackTrace();
}
}
if(checkOut(i)){
break;
}
}
}
//判断是否结束进程的方法
public boolean checkOut(int i){
if(name !=null){
return true;
}
if(i == 100){
name = Thread.currentThread().getName();
return true;
}
return false;
}
}
- Callable接口 call() 定义线程体,优点是可以抛出异常,可以定义返回值;
public class ThreadDemo05 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Match2 match = new Match2();
//通过线程池 固定大小线程池2个 static ExecutorService newFixedThreadPool(int nThreads)
//1.创建执行服务
ExecutorService server = Executors.newFixedThreadPool(2);
//2.提交任务 <T> Future<T> submit(Callable<T> task) 提交值返回任务以执行并返回表示任务的挂起结果的Future。
Future<Integer> f1 = server.submit(match);
Future<Integer> f2 = server.submit(match);
//3.获取结果
Integer result1 = f1.get();
Integer result2 = f2.get();
System.out.println(result1);
System.out.println(result2);
//4.结束服务
server.shutdown();
}
}
//比赛
class Match2 implements Callable<Integer> {
//结束标识
private String winner; //记录赢的人的名字
/*
可以抛出异常
*/
@Override
public Integer call() throws InterruptedException {
//i作为步数
for(int i=1;i<=100;i++){
//是否为兔子
System.out.println(Thread.currentThread().getName()+"正在跑第"+i+"步");
if("兔子".equals(Thread.currentThread().getName()) && i%20==0){
Thread.sleep(20);
}
//结束判断
if(checkOver(i)){
return i;
}
}
return null;
}
//结束的条件判定 返回值: true结束 false不结束
public boolean checkOver(int steps){
boolean flag = false;
//有人赢了
if(winner != null){
return true;
}
//自己赢了
if(steps==100){
winner = Thread.currentThread().getName();
return true;
}
return false;
}