java学习笔记6(下)

 21.List集合的5种遍历方式:

List<String> list = new ArrayList<>() ;
list.add("hello") ;
list.add("JavaEE") ;
list.add("i'm coming") ;
//方式1:
Object[] objects = list.toArray() ;
for(int x = 0 ; x < objects.length; x ++){
    String s = (String)objects[x] ;
    System.out.println(s) ;
}
//方式2:Collection集合的迭代器
Iterator<String> it = list.iterator() ;
while(it.hasNext()){
    String s = it.next() ;
     System.out.println(s) ;
}
//方式3:使用List集合的特有功能
for(int x = 0 ; x< list.size() ; x++){
    String s = list.get(x) ;
    System.out.println(s) ;
}
//方式4:使用列表ListIterator遍历List集合
ListIterator<String> lit = list.listIterator() ;
while(lit.hasNext()){
    String s = lit.next() ;
     System.out.println(s) ;
}
//方式5:jdk5以后 提供一个增强for循环,替代迭代器
for(String s:list){
    System.out.println(s) ;
}

22.List集合特点和Set集合有什么区别

List集合保证元素有序(存储和取出一致),Set集合无序的:不能保证迭代顺序恒久不变
List集合可以让元素重复/set集合本身就是保证元素唯一!
​
子实现类的分别的应用场景:
ArrayList
Vector
LinkedList
HashSet
TreeSet

23.List集合三个子实现类的特点:

ArrayList:
            底层数据结构是数组,数组的特点:查询快,增删慢
             查询的:通过整数索引,立即查询到元素
            从线程角度考虑:由于实现是不同步的,执行效率高,线程不安全!
            默认容量大小:10个
            扩容机制:1.5倍方式扩容
 Vector:
                底层数据结构是数组,查询快,增删慢
                线程角度:实现同步的,里面的成员方法大部分都会有synchronized同步锁,保证安全性
                安全性很高,但是执行效率低,单线程程序中,使用ArrayList替代Vector
LinkedList:
                    底层数据结构是一个链表,
                    线程角度:  不同步的,单线程中执行效率高,安全性低!
                    链表:数据域和指针域组成!
          当一些需求没有明确提示使用什么类型的时候,都是用ArrayList(单线程程序中)

24.ArrayList集合

 构造方法:
   public ArrayList():构造一个初始容量为十的空列表。
   public ArrayList(int initialCapacity):指定容量大小

25.Vector集合

在List集合中最明显的特点:线程安全
目前为止:线程安全的类(多线程中使用)
          StringBuffer/Vector/
          线程安全的方法:Collections:针对集合操作工具类
          public static <T> List<T> synchronizedList(List<T> list):保证列表同步(安全方法)
  特有功能:
         public void addElement(Object obj):添加元素
         public boolean removeElement(Object obj):直接从Vector集合中删除指定的元素
         public Object elementAt(int index):通过指定的索引值获取元素------类似于List集合中 get(int index)
         public Enumeration<Object> elements():(特有迭代器)获取Vector集合中的枚举组件接口  -----类似于  public Iterator iterator():迭代器
        boolean hasMoreElements()  ---->类似于   boolean hasNext() 判断是下一个遍历的元素
        Object nextElement()     ---类似于    Object next()     获取下一个元素 
   应用场景:
      如果环境是多线程环境,而且使用集合存储数据,保证线程安全,Vector集合!
   Vector集合遍历:7种   使用特有功能: public Object elementAt(int index) +size()
        for(int x = 0 ; x < v.size() ; x ++){
            String s = v.elementAt(x);
            System.out.println(s) ;

26.LinkedList集合

不同步,线程不安全,执行效率高; 数据结构是:链表
 特有功能:
      public void addFirst(Object e):在链表开头插入元素
      public void addLast(Object e):将元素追加到链表的末尾
      public Object getFirst():获取链表的第一个元素
      public Object getLast():获取链表的最后一个元素
     public Object removeFirst():删除链表第一个元素并获取第一个元素
     public Object removeLast():删除链表最后一个元素并获取

27.List集合嵌套应用:ArrayList<ArrayList

<Student>> :如何嵌套使用?

分析:
     0)创建出大的集合
     1)三个小集合:ArrayList<Student>,添加几个学生数据
      2)分别将三个小集合都添加到集合中
      3)遍历大集合中
          遍历小集合,分别获取信息
 举例: 有3个Java基础班,每一个班级都看成一个ArrayList<Student>,
    这个三个班级组成了一个大的集合ArrayList<ArrayList<Student>>
    获取出每一个班级的学生的姓名和年龄;
  
 public class ArrayListTest {
    public static void main(String[] args) {
​
        //创建出大的集合
        ArrayList<ArrayList<Student>> bigArray = new ArrayList<>() ;
​
        //第一个Java基础班
        ArrayList<Student> firArray = new ArrayList<>() ;
        //创建3个学生
        Student s1  = new Student("唐僧",50) ;
        Student s2  = new Student("孙悟空",44) ;
        Student s3  = new Student("猪八戒",40) ;
        //添加数据
        firArray.add(s1) ;
        firArray.add(s2) ;
        firArray.add(s3) ;
​
        //添加到大集合中
        bigArray.add(firArray) ;
​
        //第二个Java基础班
        ArrayList<Student> secArray = new ArrayList<>() ;
        //三个学生
        Student s4  = new Student("宋江",40) ;
        Student s5  = new Student("武松",35) ;
        Student s6  = new Student("鲁智深",32) ;
        secArray.add(s4) ;
        secArray.add(s5) ;
        secArray.add(s6) ;
​
        bigArray.add(secArray) ;
​
        //第三个Java基础班
        ArrayList<Student> thirdArray = new ArrayList<>() ;
        Student s7  = new Student("曹操",45) ;
        Student s8  = new Student("刘备",36) ;
        Student s9  = new Student("周瑜",33) ;
        thirdArray.add(s7) ;
        thirdArray.add(s8) ;
        thirdArray.add(s9) ;
​
        bigArray.add(thirdArray) ;
​
        //遍历 ArrayList<ArrayList<Student>>
        for(ArrayList<Student> array :bigArray){
            for(Student s :array ){
                System.out.println(s.getName()+"\t"+s.getAge());
            }
        }
    }
}
 public class Student {
    private String name ;
    private int age ;
​
    public Student() {
    }
​
    public Student(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 String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

28.Set集合

1.1无序.保证元素唯一!
  代表HashSet子实现类
  底层一个HashMap的实例,保证元素唯一(底层哈希表,和HashMap有关系),不能保证迭代顺序恒久不变!
1.2面试题::为什么HashSet<String>,添加重复的String数据,能够将元素唯一!
   hashSet集合的添加功能,add方法:间接依赖于的HashMap的put方法----->底层依赖于          hashCode()和equals()方法
   首先,要比较当前存储String类型数据的哈希码值是否相同,如果相同
   比较是内容是否一样,调用equals()方法,String类型已经重写了Object,比较内容!

29.TreeSet集合

TreeSet<E>:底层依赖于TreeMap -----Red-Black-Tree:数据结构:红黑树(自平衡的二叉树结构)  有两种排序:自然排序/比较器排序,取决于你的构造方法!
  TreeSet<Integer>(无参构造方法创建TreeSet集合对象) ---->Integer本身实现Comparable接口:compareTo方法,
TreeSet<Student>:通过无参构造方法创建对象----前提条件:给定排序条件,如果当前Student类没有实现Comparable接口,类转换异常;
解决:
    自定义对象所在的类必须实现Comparable接口的compareTo()方法,实现自己的排序规则!
    举例:,键盘录入5个学生的姓名,语文成绩,英语/数学,总分从高到低排序(自然排序)
public class TreeSetTest {
    public static void main(String[] args) {
​
        //创建TreeSet集合:无参构造方法:自然排序
        TreeSet<Student> ts = new TreeSet<>() ;
​
​
        System.out.println("录入学生信息开始: ");
        //录入5个学生
        for(int x = 1 ; x <=5 ; x ++){
            //创建键盘录入对象
            Scanner sc = new Scanner(System.in) ;
​
            //提示并录入数据
            System.out.println("请你输入第"+x+"个学生的姓名: ") ;
            String name = sc.nextLine() ;
​
            System.out.println("请你输入第"+x+"个学生的语文成绩: ") ;
            String chineseStr = sc.nextLine() ;
​
            System.out.println("请你输入第"+x+"个学生的数学成绩: ") ;
            String mathStr = sc.nextLine() ;
​
            System.out.println("请你输入第"+x+"个学生的英语成绩: ") ;
            String englishStr = sc.nextLine() ;
​
            //创建学生对象:封装学生数据
            Student s = new Student() ;
            s.setName(name) ;
            s.setChinese(Integer.parseInt(chineseStr)) ;
            s.setMath(Integer.parseInt(mathStr)) ;
            s.setEnglish(Integer.parseInt(englishStr)) ;
​
            //将学生添加集合中
            ts.add(s) ;
        }
        System.out.println("录入学生信息完毕: ") ;
        System.out.println("学生的总分从高到低排序如下: ") ;
        System.out.println("姓名\t语文成绩\t数学成绩\t英语成绩");
        //遍历集合
        for(Student s:ts){
            System.out.println(s.getName()+"\t"+s.getChinese()+"\t"+s.getMath()+"\t"+s.getEnglish());
        }
    }
}   
public class Student  implements  Comparable<Student>{
    //姓名
    private String name ;
    //语文成绩
    private int chinese ;
    //数学成绩
    private int math ;
    //英文成绩
    private int english ;
​
    public Student() {
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getChinese() {
        return chinese;
    }
​
    public void setChinese(int chinese) {
        this.chinese = chinese;
    }
​
    public int getMath() {
        return math;
    }
​
    public void setMath(int math) {
        this.math = math;
    }
​
    public int getEnglish() {
        return english;
    }
​
    public void setEnglish(int english) {
        this.english = english;
    }
​
    //计算总分
    public int getSum(){
        return chinese + math + english ;
    }
​
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", chinese=" + chinese +
                ", math=" + math +
                ", english=" + english +
                '}';
    }
    //要进行比较
    @Override
    public int compareTo(Student s) {
        //排序的主要条件:
        //总分从高到低进行排序
        int num = s.getSum() - this.getSum() ;
​
        //分析次要条件:
        //总分相同,按照语文成绩:从低到高
        int num2 = (num==0)?(this.chinese-s.chinese):num ;
        //总分相同,语文相同,按照数学成绩:从低到高
        int num3 = (num2==0)?(this.math-s.math):num2;
        //总分相同,语文相同,按照英语排
        int num4 = (num3 ==0)?(this.english-s.english):num3 ;
        //如果都相同,不一定是同一个人,按照学生的姓名进行比较(字典顺序比较)
        int num5 = (num4==0)?(this.name.compareTo(s.name)):num4 ;
        return num5;
    }
}

30.HashSet存储自定义对象如何保证元素唯一

HashSet集合的添加功能,add方法底层依赖HashMap的put方法---->hashCode()和equals方法
存储的自定义对象所在的类必须重写Object的hashCode()和equals方法,保证元素唯一!

31.获取一个类的字节码文件对象有几种方式

Object类的getClass()----->Class (class 包名.类名)
任意Java类型的class属性
package com.qf;
class Demo{}
Class c = Demo.class;

32.Map集合

Map接口---->不能实例化
  具体的子类
      HashMap<K,V>
      TreemMap<K,V>
 基本功能:
          V put(K key,V value)添加键值对元素,返回键对应的值
          void clear() 暴力删除,将Map清空
          V remove(Object key):删除指定的键,返回被删除的键对应的值
          是否包含指定的键
          boolean containsKey(Object key)
          是否包含指定的值
          boolean containsValue(Object value)
          int size():获取Map的键值对个数(元素)
          Collection<V> values():获取Map中所有的值
          Set<K> keySet():获取所有的键的集合
          V get(Object key):通过键获取值
          Set<Map.Entry<K,V>> entrySet():获取Map集合中的键值对对象.
Map集合的遍历方式有 两种:
      方式1:(通用)
             Set<K> keySet():获取所有的键的集合------>
              V  get(Object key):通过键获取值---------->
        方式2:              
               Set<Map.Entry<K,V>> entrySet():获取Map集合中的键值对对象 ------>
               K getKey() 键值对对象获取键---->  
              V getValue() 键值对对对象获取值--->

33.HashMap<K,V>集合

K键,V值----存储的一系列的键值对元素.
Map集合特点:不能包含重复的键(必须唯一),如果重复,后面的值会将前面的值覆盖
如果HashMap存储的键为自定义类型,
     那么当前自定义类型必须重写equals()和hashCode(),保证键唯一,因为Map集合针对键有效,跟值无关
 TreeMap<K,V>:针对元素(键)自然排序或者比较器排序,取决于构造方法
    public TreeMap():自然排序:
    public TreeMap(Comparator<? super K> comparator):比较器排序         

34.面试题:Map和Collection的区别?

  1)存储结构不一样
      Collection<E>,单例集合,只能存储一种引用数据类型----->理解为"光棍"
      Map<K,V>,双列集合,可以存储多个引用数据类型---->理解为"夫妻对"
  2)遍历方式不同的
      Collection:迭代器遍历---最终使用的增强for
      Map<K,V>: 通用的方式:将所有K获取到,通过键找值!
  3)有一定的关系
      Collection里面的Set的子实现类都依赖于Map实现

35.Collections类:针对集合操作的工具类:

 特有功能:
         public static void reverse(List<?> list):将List元素反转
         public static void shuffle(List<?> list):将List集合随机置                        public static <T extends Comparable<? super T>> void sort(List<T> list):针对List集合自然排序
         public static <T> void sort(List<T> list,Comparator<? super T> c):针对List集合进行比较器排序
         public static <T> int binarySearch(List<? extends Comparable<? super T>> list,T key)
         在集合中查询key元素第一次出现索引值 (集合有序!----List<Integer>
         获取集合中最大值和最小值元素
         //public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)
          public static <T> List<T> synchronizedList(List<T> list) :和多线程结合使用!
 举例:使用集合模拟斗地主的洗牌和发牌,发到每个人手上牌有序
   分析:
   1)创建牌盒
     HashMap<Integer,String>存储的编号和对应的牌
     ArrayList<Integer>单独存储编号
   2)
      int index = 0 ;
   装牌:点数,花色
          点数数组: "3","4"....,"10","J","Q","A","2"
         花色---拼接点数
          index ++ ;
          单独添加map集合添加(index,"小王") ;
          arrayList集合.add(index) ;
          index ++ ;
          单独添加map集合添加(index,"大王") ;
  3)洗牌:洗的是      ArrayList<Integer>存储编号
 
  4)发牌:发的是编号
           三个玩家/底牌 TreeSet<Integer>
              发牌的业务算法逻辑
              for(int x = 0 ; x < arrry.size() ; x ++){
             //判断
            //底牌:三张:如果当前x>=array.size()-3
             if(x>=arrry.size()-3){
                  //底牌的:索引值
                  //通过diPai获取在大的集合获取添加
                  diPai.add(arrry.get(x)) ;
                //三种情况:
              }else if(x % 3 == 0 ){
                  //情况1:----玩家1
                  plary1.add(arrry.get(x)) ;
              }else if(x % 3 == 1){
                  //玩家2
                  plary2.add(arrry.get(x)) ;
              }else if(x % 3 == 2){
                  //玩家3
                plary3.add(arrry.get(x)) ;
              }
              //x % 3==3 :发完了
         }
   5)看牌:
 public static void  lookPoker(String name,TreeSet<Integer> ts,HashMap<Integer,String> hm)
代码实现:

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.TreeSet;
public class PokerDemo {
    public static void main(String[] args) {
        //创建牌盒  使用HashMap集合<Integer,String>,Key:它的编号  Value:存储的牌
        HashMap<Integer,String> hm = new HashMap<>() ;
        //创建ArrayList<Integer>,单独存储的牌的编号
        ArrayList<Integer> array = new ArrayList<>() ;
        //装牌
        //定义花色数组
        String[] colors = {"♥","♠","♣","♦"} ;
        //定义点数数组
        String[] numbers = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"} ;
        //定义编号变量index:从0开始
        int index = 0 ;
        //拼接
        for(String number :numbers){
            for(String color:colors){
                String poker = color.concat(number);
                //将编号和进行添加
                hm.put(index,poker) ;
                array.add(index) ;
                //编号++
                index ++;
            }
        }
        //添加小王/和大王
        hm.put(index,"小王") ;
        array.add(index) ;
        index ++ ;
        hm.put(index,"大王") ;
        array.add(index) ;
        //System.out.println(array) ;//编号
        //洗牌:洗的是编号
        Collections.shuffle(array) ;
      //  System.out.println(array);
​
        //发牌:(发的是编号)发牌需要保证每个玩家手上的牌有序:使用TreeSet集合进行操作
        TreeSet<Integer> player1 = new TreeSet<>() ;
        TreeSet<Integer> player2 = new TreeSet<>() ;
        TreeSet<Integer> player3 = new TreeSet<>() ;
        TreeSet<Integer> diPai = new TreeSet<>() ;
        for(int x = 0 ; x < array.size(); x++){
            //遍历了ArrayList集合中的所有牌对应的编号
            if(x>=array.size()-3){
                //底牌
                diPai.add(array.get(x)) ;
            }else if(x % 3 == 0 ){
                player1.add(array.get(x)) ;
            }else if(x % 3 == 1){
                player2.add(array.get(x)) ;
            }else if(x % 3 == 2){
                player3.add(array.get(x)) ;
            }
        }
​
        //看牌:三个都可以看牌,看一下底牌的内容:封装成功能
        lookPoker("库里",player1,hm) ;
        lookPoker("欧文",player2,hm) ;
        lookPoker("哈登",player3,hm) ;
        lookPoker("底牌",diPai,hm) ;
​
    }
    public static void lookPoker(String name,TreeSet<Integer> ts,HashMap<Integer,String> hm){
        //输出人的名称
        System.out.print(name+"的牌是:  ") ;
        //TreeSet集合里面存储的自己的牌的编号
        for(Integer key:ts){
            //获取到每一个编号
            //在HashMap集合中通过编号找值
            String poker = hm.get(key);
            System.out.print(poker+"\t") ;
        }
        System.out.println();
    }
}

36.Thread线程

1.1何创建多个线程?
      1)创建线程---->创建进程---->创建系统资源
      但是,Java语言是不能够创建资源的,只有C语言
      2)不能直接创建系统资源,Jdk提供了一个类Thread,底层封装的
      3)java.lang.Thread:线程类(jvm能够运行应用程序并发的执行多个线程)
       A)自定义一个类继承Thread类
       B)在自定义的类中重写Thread类的run方法----run方法: 放置的耗时的代码                      (怎么调用的? 是线程启动start,通过jvm调用run方法
                 构造函数:
                      public Thread():创建线程
                     成员方法:
                     public final String getName():获取线程名称
                     public final void setName(String name):设置线程名称
        C)在main线程:用户线程中,创建当前这个的类对象---->线程对象
        启动线程:start方法
1.2面试题::Jvm是多线程的吗?
  Jvm:java虚拟机是多线程
  至少有两条线程
       一条是main线程,用户线程
       还有一个:垃圾回收线程,需要不断将堆内存中不用的对象进行回收,释放内存空间!
1.3 守护线程
public final void setDaemon(boolean on):标记某个线程是否为守护线程
 参数如果为true,就是守护线程,如果线程都是守护线程,则JVM退出
 注意事项:如果要设置某个线程为守护线程,必须在在启动线程之前,调用setDaemon(true)
1.4 Thread线程的优先级
  常量字段
          public static final int MIN_PRIORITY  = 1 最小优先级
          public static final int NORM_PRIORITY = 5 默认优先级
          public static final int MAX_PRIORITY = 10 最大优先级
          public final int getPriority():获取优先级
          public final int getPriority():设置优先级
1.5 多线程的实现方式2:
  1)自定义一个类,实现Runnable接口,
  2)重写接口中的run方法:就只有一个run
  3)在main用户线程中,创建当前类的对象,
  然后创建Thread类对象:将当前的那个类的对象作为参数传递
   构造方法
   Thread(Runnable target)分配一个新的 Thread对象。
   Thread(Runnable target, String name):创建线程类对象,将资源类对象作为参数传递,并且给线程设置名称
   举例 电影有三个窗口,总共100张电影票被三个窗口售卖,请使用多线程序的方式实现

public class SellTicketDemo {
    public static void main(String[] args) {
​
        //创建资源类对象
        SellTicket st = new SellTicket() ;
​
        //创建三个线程,并给线程起名字
        //Thread(Runnable  target ,String name)
        Thread t1 = new Thread(st,"窗口1") ;
        Thread t2 = new Thread(st,"窗口2") ;
        Thread t3 = new Thread(st,"窗口3") ;
​
        //启动线程
        t1.start() ;
        t2.start() ;
        t3.start() ;
}
}
public class SellTicket implements  Runnable{ //谁实现Runnable接口:谁就是资源类!
    //100张票
    public static int tickets = 100 ;
    //创建一把锁
    private Object obj = new Object() ;
    private Demo demo = new Demo() ;
    @Override
    public void run() {
        //模拟一直有票
        //t1,t2,t3
        while(true){
            /**
             *  synchronized(锁对象){
             *                               多条语句对共享数据进行操作
             *                            }
             */
                //t1,t2,t3睡眠醒来之后
           // synchronized (new Object()){//锁对象:不是同一个锁对象,每个线程new Object()用的自己的锁
           synchronized (demo){//t1,t2,t3
                //判断当前票
                if(tickets>0){
                    //让线程睡眠100毫秒
                    try {
                        //t1
                        //可能出现问题
                        Thread.sleep(200); //参数为毫秒数
                    } catch (InterruptedException e) {
                        e.printStackTrace(); //jvm就会将异常信息打印在控制台上
                    }
                    System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickets--)+"张票");
                }
            }
        }
    }
}
//自定义的类
class Demo{}
​
1.6 多线程安全问题的校验标准:
      1)检查你的程序是否为多线程环境      是
      2)是否存在共享数据:                 存在
      3)是否有多条语句对共享数据进行操作  也存在
     如何解决呢?
        现在环境就需要使用多线程实现,1)不能更改
        必须存在共享数据,因为三个线程共享一个内存区域, 2)标准不能被更改
         Java提供了:使用同步代码块 将 多条对共享数据的操作包裹起来,需要 更改3)
                 synchronized(锁对象){
                       多条语句对共享数据进行操作
                          }
          锁对象:可以是任意的Java类对象(jdk提供的任意类或者自定义类型)
           必须多个线程使用的 是同一个锁对象!   理解为:"火车上上厕所的门开和关!"
1.7什么是同步方法:
     如果一个方法中一进来就是同一个同步代码块,那么可以将synchronized定义在方法声明上,同步块不需要了!
    格式:
            权限修饰符 synchronized 返回值类型 方法名(形式参数列表){
                ...
              }
      同步方法的锁对象是谁:      this:代表所在的那个类的对象的地址值引用!
      如果当前这个方法:是一个静态方法---可以定义静态的同步方法,锁对象是谁呢?
                          静态跟类相关的---反射有关系   类名.class
同步代码块synchronized(锁对象){多条对共享数据的操作}
  前提条件:锁对象必须是同一个锁(同一个对象)
1.8   死锁现象:多个线程在互相抢占资源数据的时候,出现了线程互相等待的情况!
      原因:必须保证多个线程 "共享同一个资源对象"------>生成者消费者模式思想操作
  举例:模拟生成者和消费者模式
  
public class ThreadDemo {
    public static void main(String[] args) {
        //创建一个学生对象
        Student s = new Student() ;
        //创建生产者资源类对象
        SetThread st = new SetThread(s) ;
        //创建消费者资源类对象s
        GetThread gt = new GetThread(s) ;
        //创建线程类对象
        Thread t1 = new Thread(st) ;
        Thread t2 = new Thread(gt) ;
        //启动线程
        t1.start() ;
        t2.start() ;
    }
}
//生产者类
public class SetThread implements  Runnable {
    //Student s = new Student() ;
    private Student s ; //声明学生变量s
    public SetThread(Student s){
        this.s = s ;
    }
    //统计变量
    private int x = 0 ;
    @Override
    public void run() {
        while(true){
            //t1
            synchronized (s){
                //判断:
                //如果当前生产者没有数据,先等待产生数据
                if(s.flag){
                    try {
                        s.wait(); //wait()方法为什么定义Object类中? 因为锁对象可以是任意的Java类对象 (包括Object)
                                    //     //wait()一旦被调用,会立即释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                   }
                }
                if(x % 2 ==0){
                    s.name ="高圆圆" ;
                    s.age = 42 ;
                }else {
                    s.name = "李云迪";
                    s.age = 39;
                }
                //改变标记:有数据了
                //改变标记
                s.flag = true ;
                //调用通知对方:唤醒对方线程
                s.notify() ;
            }
            x++ ;//原子性操作
        }
    }
}
//消费者类
public class GetThread implements Runnable {
    //声明学生变量s
    private Student s ;
    public GetThread(Student s) {
        this.s =  s ;
    }
    //Student s= new Student() ;
    @Override
    public void run() {
        //使用学生数据
        //System.out.println(s.name+"-"+s.age) ;
        //不断的去使用数据
        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() ;
            }
​
        }
    }
}
 学生类
public class Student {
    String name ; //姓名
    int age ;//年龄
    boolean flag ; //默认没有数据,通过这标记信号:表示是否存在数据
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值