黑马程序员_Java学习日记第四天-线程、Java1.5的新特性

------- android培训、 java培训、期待与您交流! ----------

线程

 

创建线程的两种方式:

第一种

继承thread类,新建子类

第二种

1 定义类实现Runnable接口

2 覆盖Runnable接口中的run方法

3 通过thread类建立线程

4 将Runnable接口的子类对象当作实际参数传递给thread类的构造函数

5 调用thread类的start方法开启线程。

 

线程的基本概念、线程的基本状态以及状态之间的关系

一个程序中可以有多条执行线索同时执行,一个线程就是程序中的一条执行线索,每个线程上都关联有要执行的代码,即可以有多段程序代码同时运行,每个程序至少都有一个线程,即main方法执行的那个线程。如果只是一个cpu,它怎么能够同时执行多段程序呢?这是从宏观上来看的,cpu一会执行a线索,一会执行b线索,切换时间很快,给人的感觉是a,b在同时执行,好比大家在同一个办公室上网,只有一条链接到外部网线,其实,这条网线一会为a传数据,一会为b传数据,由于切换时间很短暂,所以,大家感觉都在同时上网。
状态:就绪,运行,synchronized阻塞,wait和sleep挂起,结束。wait必须在synchronized内部调用。
调用线程的start方法后线程进入就绪状态,线程调度系统将就绪状态的线程转为运行状态,遇到synchronized语句时,由运行状态转为阻塞,当synchronized获得锁后,由阻塞转为运行,在这种情况可以调用wait方法转为挂起状态,当线程关联的代码执行完后,线程变为结束状态。

 

多线程有几种实现方法?同步有几种实现方法?

多线程有两种实现方法,分别是继承Thread类与实现Runnable接口
同步的实现方法有两种,分别是synchronized,wait与notify
wait():使一个线程处于等待状态,并且释放所持有的对象的锁。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常,sleep不会释放所持有对象的锁。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

举例(实现Runnable接口)

 

class Ticketimplements Runnable

{

    privateintnumber = 100;

    Object obj=new Object();

    publicvoid run()

    {

       while(true)

       {

           synchronized(obj)

           {

           if(number>0)

           {

           try{Thread.sleep(10);}

           catch(Exception e){}

           System.out.println(Thread.currentThread().getName()+" sell ticket"+number--);

           }

           }

           }

    }

}

publicclass ThreadDemo {

    publicstaticvoid main(String[] args) {

       Ticket t=new Ticket();

       Thread s1=new Thread(t);

       Thread s2=new Thread(t);

       Thread s3=new Thread(t);

       Thread s4=new Thread(t);

       s1.start();

       s2.start();

       s3.start();

       s4.start();

    }

}

 

1.由懒汉式联想到的问题

 

class SingleimplementsRunnable

      {

      privatestatic Singles=null;

      Single()

      {

      System.out.println(Thread.currentThread().getName()+"---newSingle()");

      }

      publicvoid run()

      {

             while(true)

             {

             if(s==null)

             {

                    System.out.println(Thread.currentThread().getName()+"---entered,waiting...");

                    synchronized(Single.class)

                    {

                           if(s==null)

                             {//此处的大括号,用于验证抢到执行权的线程的执行过程,如果有两个线程进入第一层null循环,如果不加此处的大括号,会出现如下结果

main---new Single()
Thread-0---entered,waiting... //这里线程0先进来,拿到锁,在new Single()之后,执行权被Thread-1拿走,但Thread-1没锁,等Thread-0执行完再执行
Thread-0---new Single()
Thread-1---entered,waiting...
Thread-0---entered
Thread-0---out
Thread-1---entered
Thread-1---out

如下结果

main---new Single()
Thread-0---entered,waiting... //这里锁已经被线程0拿到,然后,线程1抢到执行权,因为锁在线程0手里,只能等到线程0执行完,线程1才能执行
Thread-1---entered,waiting...
Thread-0---new Single()
Thread-0---entered
Thread-0---out
Thread-1---entered
Thread-1---out

以及如下结果

main---new Single()  //仍然是线程0先拿到执行权并拿到锁,在打印entered之后,线程1进入,无锁,等待线程0执行完再执行
Thread-0---entered,waiting...
Thread-0---new Single()
Thread-0---entered
Thread-1---entered,waiting...
Thread-0---out
Thread-1---entered
Thread-1---out

                                  s=newSingle();

                                  System.out.println(Thread.currentThread().getName()+"---entered");

                        }

                 System.out.println(Thread.currentThread().getName()+"---out");

                    }

             }

             }

      }

      }

      publicclass LazyTest

      {

      publicstaticvoidmain(String[]args)throwsException

      {

             Singlet=new Single();

             Threadt1=new Thread(t);

             Threadt2=new Thread(t);

             t1.start();

             t2.start();            

      } 

2.死锁举例

class DeadLock implements Runnable
{
 private boolean flag=true;
 DeadLock(boolean flag)
 {
  this.flag=flag;
 }
 public void run()
 {
  if(flag)
  {

   synchronized(Mylock.locka)
   {
    System.out.println(Thread.currentThread().getName()+"---get locka");
    System.out.println(Thread.currentThread().getName()+"---if locka");
    synchronized(Mylock.lockb)
    {
     System.out.println(Thread.currentThread().getName()+"---entered if lockb");
    }
   }
  }
  else
  {
   
   synchronized(Mylock.lockb)
   {
    System.out.println(Thread.currentThread().getName()+"---get lockb");
    System.out.println(Thread.currentThread().getName()+"---else lockb");
    synchronized(Mylock.locka)
    {
     System.out.println(Thread.currentThread().getName()+"---entered else locka");
    }
   }
  }
 }
}
class Mylock
{
 static Object locka=new Object();
 static Object lockb=new Object();
}
public class JustForTest
{
 public static void main(String args[]) throws Exception
 {
  Thread t1=new Thread(new DeadLock(true));
  Thread t2=new Thread(new DeadLock(false));
  t1.start();
//  Thread.sleep(1);
  t2.start();
 }
}

打印结果为:

Thread-0---get locka //线程0先抢到执行权,线程0拿到locka锁
Thread-1---get lockb //这时被线程1抢到执行权,线程1拿到lockb锁
Thread-0---if locka //执行权被线程0抢回,并输出if locka,之后线程0要继续执行,则必须拿到锁lockb,因为lockb锁已经被线程1拿到并且方法未执行完,线程1不会释放锁,转到线程1运行
Thread-1---else lockb //线程1运行并打印else lockb,线程1要继续运行,则需拿到locka锁,而locka锁在线程0处,线程0方法未执行完不能释放locka锁。于是线程0和线程1都需要对方的锁才能执行完,而双方因为方法体未执行完都不能释放自己的锁,于是出现了死锁

 

代码举例(多线程之间通信):

class res

{

    private Stringname;

    private Stringsex;

    booleanflag =false;

    publicsynchronizedvoid set(String name,String sex)

    {

       if(flag)

           try{this.wait();}

       catch(InterruptedException e){};

       this.name=name;

       this.sex=sex;

       this.flag=true;

       this.notify();

    }

    publicsynchronizedvoid output()

    {

       if(!flag)

           try{this.wait();}

       catch(InterruptedException e){};

       System.out.println(name+"的性别是---"+sex);

       this.flag=false;

       this.notify(); 

    }

}

class InPutimplements Runnable

{

    private resr;

    InPut(res r)

    {

       this.r=r;

    }

        inta=0;

       publicvoid run()

       {

           while(true)

              {

                  if(a==0)

                  {

                     r.set("Mike","Male");

                  }

                  else

                  {

                     r.set("莉莉","女");

                  }

                  a=(a+1)%2;

              }

       }

}

class OutPutimplements Runnable

{

    private resr;

    OutPut(res r)

    {

       this.r=r;

    }

    publicvoid run()

    {

       while(true)

       {

           r.output();

       }

    }

}

publicclassInputOutput

{

    publicstaticvoid main(String[] args)

    {

       res r=new res();

       new Thread(new InPut(r)).start();

       new Thread(new OutPut(r)).start();

    }

}

 

JDK1.5新特性:

提供了多线程升级解决方案,

将同步Synchronized替换成现在的lock操作,

Object中的waitnotifynotifyall替换成现在的condition对象,

该对象可以对lock锁进行获取

 

举例

 

importjava.util.concurrent.locks.*;

class resource

{

    private Stringname;

    intnum=1;

    booleanflag =false;

    private Locklock=new ReentrantLock();

    private Conditioncondition_pro=lock.newCondition();

    private Conditioncondition_con=lock.newCondition();

    publicvoid set(String name)throws InterruptedException

    {

       lock.lock();

       try

           {

              while(flag)

              condition_pro.await();

              this.name=name+"--"+num++;            System.out.println(Thread.currentThread().getName()+"生产者"+this.name);

              flag=true;

              condition_con.signal();

           }

       finally

       {

           lock.unlock();

       }

    }

    publicvoid output()throws InterruptedException

    {

       lock.lock();

       try

       {

           while(!flag)

           condition_con.await();

           System.out.println(Thread.currentThread().getName()+"消费者------"+this.name);

           flag=false;

           condition_pro.signal();

       }

       finally

       {

           lock.unlock();

       }

    }

}

class Producerimplements Runnable

{

    private resourcer;

    Producer(resource r)

    {

       this.r=r;

    }

       publicvoid run()

       {

           while(true)

           {

              try{r.set("商品");}

              catch(Exception e){}

           }

       }

}

class Consumerimplements Runnable

{

    private resourcer;

    Consumer(resource r)

    {

       this.r=r;

    }

    publicvoid run()

    {

       while(true)

       {

           try

           {

              r.output();

           }

           catch(Exception e){}

       }

    }

}

publicclass ProducerConsumerDemo

{

    publicstaticvoid main(String[] args)

    {

       resource r=new resource();

       Producer pro=new Producer(r);

       Consumer con=new Consumer(r);

       Thread t1=new Thread(pro);

       Thread t2=new Thread(con);

       Thread t3=new Thread(pro);

       Thread t4=new Thread(con);

       t1.start();

       t2.start();

       t3.start();

       t4.start();

    }

}

 

如何让线程自动结束?代码如下(在main函数中控制,让run方法停下)

 

class Runimplements Runnable

{

    booleanflag=true;

    publicsynchronizedvoid run()

    {

       while(flag)

           try{wait();}

           catch(Exception e)

           {System.out.println(Thread.currentThread().getName()+"线程启动");

           flag=false;

           }

    }

    publicvoid ChangeFlag()

    {

       flag=false;

    }

    }

publicclass StopThread

{

    publicstaticvoid main(String[] args)throws InterruptedException {

       Run run=new Run();

       Thread t1=new Thread(run);

       t1.start();

       int num=0;

       while(true)

       {

           if(num++ == 50)

           {

              t1.interrupt();

              break;

           }

           System.out.println(Thread.currentThread().getName()+num);

       }

    }

}

 

 

Stringreplace方法调用举例:

publicclass StringMethods {

   

    publicstaticvoid main(String[] args)

    {

       String s="HelloJava";

       String s1=s.replace("Java","viva");

       String s2=s.replace("","e");

       sop(s);

        sop(s1);

       sop(s2);

    }

    publicstaticvoid sop(Object obj)

    {

       System.out.println(obj);

    }

}

 

 

JDK1.5之后增加了StringBuilder功能,但不保证同步。StringBuffer是线程同步的。

建议多线程用StringBuffer,单线程用StringBuilder(效率高)。

 

基本数据类型转换成字符串:

基本数据类型+"";

基本数据类型.toString(基本数据类型值)

Integer.toString(34);//34转换成"34"

 

字符串转基本数据类型:

xxxa=Xxx.parsexxx(String);

例如int a=Integer.parseInt("123");

 

 

JDK1.5版本后的新特性:

 

泛型:

JDK1.5版本以后出现的新特性,用于解决安全问题,是一个安全机制。

好处

1.将运行时期出现的问题ClassCastException转移到了编译时期。方便于程序员解决问题,让运行时期问题减少,安全。

2.避免了强制转换的麻烦。

 

在使用java提供的对象时,什么时候写泛型呢?

 

通常在集合框架中很常见。

只要见到<>就要定义泛型。

 

什么时候定义泛型类?

当类中要操作的应用数据类型不确定时,早期定义Object来完成扩展,现在定义泛型来扩展。

 

泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。

 

泛型类举例:

 

classUtils

{

private Q q;

public void setObject(Q q)

{

this.q=q;

}

public Q getObject()

{

return q;

}

}

 

 

为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。

class Demo

{

public void show(T t)

{

  System.out.println(t);

}

public void print (Q q)

{

  System.out.println(q);

}

}

publicclassGenericDemo

{

    publicstaticvoid main(String[] args)

    {

        Demod=newDemo();

        d.show("haha");

        d.show(new Integer(4));

        d.print("heihei");

    }

}

运行结果:haha

4

heihei

泛型类和泛型方法的结合:

class Demo

{

publicvoidshow(T t)

{

    System.out.println(t);

}

public voidprint (Q q)

{

    System.out.println(q);

}

publicstaticvoidget (W w) //静态方法不可以访问类上定义的泛型。

//如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上。

{

    System.out.println(w);

}

}

publicclassGeneric

{

    publicstaticvoid main(String[] args)

    {

        Demo d=newDemo ();

        d.show("haha");

        d.print("heihei");

        d.print(new Integer(5));

        Demo.get("xixi");

    }

}运行结果:haha

heihei

5

Xixi

 

?通配符:也可以理解为占位符。

泛型的限定:

ExtendsE:可以接收E类型或者E类型的子类型。上限。

SuperE:可以接收E类型或者E类型的父类型。

 

通配符使用举例:

import java.util.*;

 

class person1

{

private Stringname;

privateintage;

person1(String name,int age)

{

    this.name=name;

    this.age=age;

}

public String getName()

{

    returnname;

}

publicint getAge()

{

    returnage;

}

}

class student1extends person1

{

private Stringname;

privateintage;

private Stringsex;

student1(String name,int age,String sex)

{

    super(name,age);

    this.sex=sex;

}

public String getSex()

{

    returnsex;

}

}

publicclassGenericDemo

{

    publicstaticvoid main(String[] args)

    {

        ArrayList al=new ArrayList();

        al.add(new person1("zhangsan1",17));

        al.add(new person1("zhangsan2",18));

        al.add(new person1("zhangsan3",27));

        printconn(al);

        ArrayList all=new ArrayList();

        all.add(new student1("lisi1",17,"male"));

        all.add(new student1("lisi2",27,"female"));

        all.add(new student1("lisi3",37,"male"));

        printconn(all);

    }

    publicstaticvoidprintconn(ArrayListextends person1> al)

    {

         Iteratorextends person1> it=al.iterator();

         while(it.hasNext())

         {

            System.out.println(it.next().getName()); 

         }

    }

}

 

高级for循环

 

格式:

For{数据类型变量名:被遍历的集合(collections)或者数组}

{}

对集合进行遍历,只能获取集合元素,但是不能对集合进行操作。

迭代器除了遍历,还可以进行remove集合中元素的操作。

如果是用ListIterator,还可以在遍历过程中对集合进行增删改查的动作。

 

传统for循环和高级for循环有什么区别呢?

高级for有一个局限性,必须有被遍历的目标。

建议在遍历数组的时候,还是使用传统for,因为传统for可以定义角标。

 

代码举例:

for(String s:arr1)

    {

       System.out.println(s);

    }

    int[] arr2={1,65,9};

    for(int s:arr2)

    {System.out.println("s="+s);}

 

 

    HashMap hm=new HashMap ();

    hm.put("a",1);

    hm.put("v",3);

    hm.put("y",6);

    Set arr2=hm.keySet();

    for(String i:arr2)

    {

       System.out.println(i+"::"+hm.get(i));

    }

    for(Map.Entryi:hm.entrySet())

    {

       System.out.println(i.getKey()+"---"+i.getValue());

      

    }

 

可变参数:

其实就是上一种数组参数的简写形式,不用每一次都手动的建立数组对象。

只要将要操作的元素作为参数传递即可,隐式将这些参数封装成了数组。

 

方法的可变参数:

在使用时注意,可变参数一定要定义在参数列表的最后面。

 

static Import  静态导入

当类名重名时,需要指定具体的包名。

当方法重名时,指定具体所属的对象或类名。

静态导入可以简化书写,在导入相应的类之后,可以直接调用该类的方法和字段,而不需要通过类名.方法或类名.字段的形式访问,例如导入Math类,

sqrt(pow(x, 2), pow(y, 2));

看起来比

Math.sqrt(Math.pow(x, 2), Math.pow(y, 2));

要清晰的多,尤其是在大量使用Math类的方法时。导入Calendar类,

if(d.get(DAY_OF_WEEK) == MONDAY)

看起来比

if(d.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY)

容易多了。

 

//Integerx=new Integer(4);

Integerx=4;(自动装箱)需要判断x是否为null !!!

X=x+2;//对象加整数(自动拆箱)

 

Integerx=128;

Integery=128;

sop("x==y:"+(x==y)+";");

//结果为false

 

Integera=127;

Integerb=1278;

sop("a==b:"+(a==b)+";");

//结果为true,因为在JDK1.5之后,如果数值在byte范围内并已经存在,系统不会开辟新的存储空间。

 

-------android培训、java培训、期待与您交流! ----------

你可能感兴趣的:(Java编程)