集合基础(三),线程

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;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值