黑马程序员_java基础二(线程和集合)

来源:互联网 发布:js 工作流引擎 编辑:程序博客网 时间:2024/05/29 21:17
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------

线程

线程基本概念

1.线程:一个正在执行的程序。

2.java虚拟机运行的时候,至少有两个线程在运行,一个是主线程,另一个是垃圾回收线程。

3.线程的创建方法有两中,一种继承Thread,一种实现Runnable接口。具体示例代码API文档有。

4.线程中start方法包含了两个动作。第一启动了线程。第二运行了run方法,run方法里面存储线程要运行的代码

5.demon demon=new domo();传进对象就创建了一个线程,要start才是启动线程。

线程的运行状态

1.被创建:new一个线程对象。

2.运行:既有运行资格,也有执行权。

3.睡眠(冻结):具备运行资格,但是没有执行权。

4.阻塞状态:没有执行资格。

5.消亡:挂了。


自己画的一张图。

获取当前线程和线程名称

多线程运行出现安全问题

问题原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另外一个线程参与进来执行。导致共享数据错误。

解决办法:对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。

同步代码块:synchronized(对象){ 需要被共享的代码}

的原理:当线程进入同步代码块时,先判断锁是否是开着的,开着的就可以进来,进来后,把锁锁上,直到执行完的时候,才会释放锁。

 同步的前提:

1.必须要有两个或者两个以上的线程。

2.必须是多个线程使用同一个锁

的弊端:多个线程需要判断锁,较为消耗资源。

同步函数:public synchronized void show(){}

非静态同步函数的锁是this。函数需要被对象调用,那么函数都有一个所属对象的引用。

如果同步函数被静态修饰后,使用的锁是class.静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。

synchronized(类名.class)

死锁:

模拟一个死锁程序。

public class DeadLockDemon {  public static void main(String[] args) {new Thread(new DeadLockTest(true)).start();new Thread(new DeadLockTest(false)).start();}}class DeadLockTest implements Runnable {/*Object obj1 = new Object();Object obj2 = new Object();*/boolean flag;DeadLockTest(boolean flag) {this.flag = flag;}public void run() {if (flag) {while(true){synchronized (Lock.obj1) {System.out.println(" if...... obj1");try {Thread.sleep(40);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}synchronized (Lock.obj2) {System.out.println("if......obj2");}}}} else {while(true){synchronized (Lock.obj2) {System.out.println(" else...... obj1");synchronized (Lock.obj1) {System.out.println("else......obj2");}}}}}}class Lock{//要把锁定义到外面,因为定义在了里面,初始化的时候,两个线程的obj1锁各不是同一把锁了。static Object obj1=new Object();static Object obj2=new Object();}
线程间通讯:其实就是多个线程在操作一个资源,但操作动作不同
等待唤醒进制

wait():

notify():

notifyAll():

上门三个方法都使用在同步中,因为要对持有监视器(锁)的线程操作。所以要使用在同步中,因为只有同步还具有锁。

为什么这些操作线程的方法要定义Object类中呢?

因为这些方法在操作同步中线程时,都必须要标识它们所操作的线程只有的锁,只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒。

不可以对不同锁中的线程进行唤醒。也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中。

wait后,线程就会存在线程池中,notify后就会将线程池中的线程唤醒。notifyAll();唤醒线程池中所有的线程。

消费者与生产者实例:

1.为什么要定义while判断标记。原因:让被唤醒的线程再一次判断标记。

2.为什么要定义为notifyAll。因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。

package com.study.two;public class ProducerConsumerDemon {public static void main(String[] args) {Resource r=new Resource();Thread t1=new Thread(new Producer(r));Thread t2=new Thread(new Producer(r));Thread t3=new Thread(new Consumer(r));Thread t4=new Thread(new Consumer(r));t1.start();t2.start();t3.start();t4.start();}}class Resource{private String name;private int count=1;private boolean flag=false;public synchronized void set(String name){this.name=name;while(flag){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(name+"--消费者-"+(count++));flag=true;this.notifyAll();}public synchronized void get(){while(!flag){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(name+"----生产者-----"+count);flag=false;this.notifyAll();}}class Producer implements Runnable {Resource res;Producer(Resource res) {this.res = res;}public void run() {while(true) {res.set(Thread.currentThread().getName()+"生产者");}}}class Consumer implements Runnable {Resource res;Consumer(Resource res) {this.res = res;}public void run() {while(true) {res.get();}}}
jdk1.5中提供了多线程的升级解决方案。将同步synchronized替换成现实的Lock操作。将Object中的wait,notify,notifyall,替换成对象condition对象。

该对象可以lock锁,释放锁。

如何停止线程?

只有一种,run方法结束。开启多线程运行,运行代码通常是循环结构。

只要控制住循环,就可以让run方法结束,也就是线程结束。

特殊情况:

当线程处于了冻结状态。就不会被读取到标记。那么线程就不会结束。

当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除。强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。

Thread类提供该放inerrupt();

setDaemon():守护线程就是后台线程,后台线程会在前台线程结束的时候会自动结束。

join:等到A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完了,A才会执行。join可以用来临时加入线程执行。

线程组:谁启动这个线程,就属于哪个线程组。

线程优先级:setPriority();[1,5,10]代表设置线程抢到资源的频率。

yield():临时释放执行权。

线程实现:可以匿名内部类的继承或者实现接口的方法。

集合

String 类

1.字符串是一个特殊的对象。字符串一旦初始化就不可以被改变。

2.

public static void main(String[] args) {String str="abc";String str1=new String("abc");String str2="abc";System.out.println(str==str1);//falseSystem.out.println(str2==str);//true}
分析:第一个 str在栈中创建了一个引用,指向堆,堆里面存放了"abc".

             str1因为是new String(),所以,在堆中新创建一块空间存放"abc",然后栈中的引用指向堆中的“abc",注意,这个"abc"和上面的”abc"是不一样的,str不等于str1的。

             第三个str2发现了堆中已经存在了“abc",所以,栈中的引用直接指向第一个堆中的”abc",所以str2==str3。

3.StringBuffer:字符串String的组成原理就是通过该类实现的。StringBuffer可以对字符串内容就行增删。

                         StringBuffer是一个容器。很多方法与String相同。StringBuffer是可变长度的

4.jdk1.5出现一个StringBuilder,区别是:StringBuffer是同步的,StringBuilder是非同步的。

5.自动拆箱装箱中Integer的小问题:

    public static void main(String[]args){    //在-128~127 之外的数,不自动拆箱装箱,所以这时候比较的是内存地址     Integer i1 = 200;       Integer i2 = 200;               System.out.println("i1==i2: "+(i1==i2));    //结果为false                    // 在-128~127 之内的数,自动拆箱装箱,比较的是基本数据类型的值     Integer i3 = 100;       Integer i4 = 100;       System.out.println("i3==i4: "+(i3==i4));   //结果为true       }

集合类

1.为什么出现集合类?

   面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。

2.数组和集合类同时容器,有何不同?

 数组虽然也可以存储对象,但是长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。

3.集合类的特点。

 集合只用于存储对象,集合长度可变,集合可以存储不同类型的对象。

4.下面贴一张毕向东老师的集合框架构成和分类:



Collection接口有两个子接口:List,Set

List:可存放重复元素,元素存取是有序的。

Set:不可以存放重复元素,元素存取是无序的。

Vector:线程安全,但速度慢,已经被ArrayList取代。

ArrayList:线程不安全,查询速度快。

LinkedList:链表结果,增删速度快。

Set接口常用的两个类:

HashSet:线程不安全,存取速度快。

                    通过equals方法和hashCode方法保证元素的唯一性。

TreeSet:线程不安全,可以对Set集合中的元素进行排序。

                   通过compareTo或者compare方法来保证元素的唯一性,元素是以二叉树的形式存放的。

注意:让元素自身具备比较性,只要让元素实现comparable接口,覆盖compareTo方法即可。但是如果元素自身不具备比较性,或是不是所需要的,这时候可以自定比较器方式,这时可以让集合自身具备比较性,定义一个类实现Comparator接口,覆盖compare方法,将该Comparator接口子类对象作为实际参数传递给TreeSet集合构造函数即可。

jdk1.5后出现了泛型:

泛型的特点:提高了程序的安全性,将运行期遇到的问题转移到了编译器,省去了类型强转的麻烦,优化了程序设计。

Map集合

Map与Collection 在集合框架中属于并别存在。

Map存储的是键值对。

Map存储元素使用的是put方法,Collection使用的是add方法。

Map集合没有直接取出元素的方法,而是先转成Set集合,再通过迭代获取元素。

Map集合中键要保证唯一性。

Map集合常用的类:

Hashtable:线程安全,速度慢,不允许存放null键,null值,以被hashMap取代了

HashMap:线程不安全,速度快,允许存放null键和null值

TreeMap:对键进行排序,排序原理与TreeSet相同。

jdk1.5新特性:增强for循环。


---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
0 0