现在的位置: 首页 > 综合 > 正文

java基础_Day11

2017年11月05日 ⁄ 综合 ⁄ 共 10302字 ⁄ 字号 评论关闭

1,线程概念:

          进程:是一个正在执行中的程序。
          线程:每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫做一个控制单元。线程就是进程中一个独立的控制单元。
          一个进程中至少有一个线程。
          JVM启用的的时候会有一个进程java.exe;该进程中至少有一个线程负责java程序的执行,而且这个线程运行的代码就存在于main方法中。该线程称之为:主线程。
          扩展:其实更细节的说明JVM,JVM启动不止一个线程,还有负责垃圾回收的线程。多线程可以提高程序运行的效率。例如:下载。

2,创建线程-继承Thread类:
          1,创建步骤:创建类继承Thread;覆盖run方法;调用start方法(该方法负责调用run方法,并且开启线程)
          2,eg:
                  class Demo11 extends Thread

{

     public void run()

     {

          for(int x=0;x<70;x++)

               System.out.println("Demo---run"+x);

     }

}

class Demo

{

     public static void main(String[] args)

    { 

Demo11 d = new Demo11();//创建了一个对象就相当于创建了一个线程。

d.start();//开启线程并且调用了run方法。

d.run();//仅仅是对象调用run方法,并没有开启线程。

          for (int x=0;x<90;x++)

               System.out.println("Hello World!"+x);     

     }

}    

结论:

                    每次运行结果都不一样。

                    因为多个线程在抢夺cpu执行权,谁抢到,cpu就执行谁。至于执行多久,cpu说了算。

明确一点:其实在某一个时刻,只能有一个程序在运行(多核除外),但是cpu在做着快速切换,达到看起来是同时执行的效果。


3,run和start的特点:

1,为什么要继承Tread,覆盖run方法?

      run方法用于存储线程要运行的代码,让线程运行。 

2,d.start();//开启线程并且调用了run方法。

      d.run();//仅仅是对象调用run方法,并没有开启线程。

3,线程运行的状态:

     被创建:创建一个Thread或者其子类对象。

     运行:调用start()方法。既有执行资格又有执行权。

     冻结:sleep(time),time结束后,进程恢复;wait(),notify()来唤醒线程。放弃执行资格。被唤醒或者时间到了以后先回到阻塞状态。

     消亡:sop();run方法结束。

     临时状态(阻塞):具备执行资格,但是没有cpu执行权


4,获取线程对象、名称:

线程都有自己默认的名称,Thread-编号  该编号从0开始。

static Thread currentThread():获取当前线程对象。

getName():获取线程名称

setName():修改线程名称,也可以通过构造函数传递参数来修改。

eg:     

class Demo11 extends Thread

{

     //private String name;

     Demo11(String name)

     {

          //this.name=name;

          super(name);

     }

     public void run()

     {

          for(int x=0;x<70;x++)

          System.out.println((Thread.currentThread()==this)+"---"+this.getName()+"---run"+x);

     }

}


class Demo

{

     public static void main(String[] args)

     { 

          Demo11 d1 = new Demo11("one--");

          Demo11 d2 = new Demo11("two++");

          d1.setName("hahahahahhahahha");

          d1.start();

          d2.start();

          for (int x=0;x<90;x++)

          System.out.println("Hello World!"+x);

     }

}

eg2:   

class Ticket extends Thread

{

//     private int tick = 100;

     private static int tick = 100;

     public void run()

     {

          while(true)

          {

               if(tick>0)

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

          }    

     }

}


class TickedDemo

{

     public static void main(String[] args)

     {

          Ticket t1 = new Ticket();//一个线程有100张票,一共卖出400张票。

//          Ticket t2 = new Ticket();

//          Ticket t3 = new Ticket();

//          Ticket t4 = new Ticket();

          t1.start();//java.lang.IllegalThreadStateException;无效线程状态异常。

          t1.start();         

          t1.start();         

          t1.start();//一个窗口在卖票。。

//          t2.start();

//          t3.start();

//          t4.start();

          //System.out.println("Hello World!");

     }

}


5,创建线程:实现Runnable接口

     1,步骤:
               1,创建类实现Runnable接口
               2,覆盖Runnable接口中的run方法
                         将线程要运行的代码存放在该run方法中
               3,创建该类的对象。
               4,通过Thread类创建线程,并将Runnable接口的子类对象作为参数传递给Thread类的构造函数
                         因为,自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去指定对象的run方法
               5,开启线程
     2,继承跟实现方式的区别是什么?
               实现的好处:实现避免了java单继承的局限性
               线程代码位置不同:
                    继承Thread:线程代码存放在Thread子类的run方法中
                    实现Runnable:线程代码存放在接口的子类的run方法中
     3,eg:           
   

class Ticket2 implements Runnable

{

     private int tick = 100;

     public void run()

     {

          while(true)

          {

               if(tick>0)

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

          }    

     }

}


class TickedDemo2

{

     public static void main(String[] args)

     {

          Ticket2 t = new Ticket2();


          Thread t1 = new Thread(t);

          Thread t2 = new Thread(t);

          Thread t3 = new Thread(t);

          Thread t4 = new Thread(t);

          t1.start();

          t2.start();

          t3.start();

          t4.start();

     }

}

          
6,多线程的安全问题:

         try{Thread.sleep(10);}catch(Exception e){}
 发现打印出了0,-1,-2等错票

  问题的原因:

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

  

   解决办法:

      对多条操作共享数据的语句,只能让一个线程都执行完,在执行的过程中,其他线程不能参与运算。java中解决多线程安全问题的方法是:同步代码块儿:

     synchronized(对象)      

     {需要被同步的代码}

 eg:         

class Ticket2 implements Runnable

{

     private int tick = 10000;

     Object obj = new Object();

     public void run()

     {

          while(true)

          {    

               synchronized(obj)

               {    

                    if(tick>0)

                    {

                         try{Thread.sleep(10);}catch(Exception e){}

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

                    }

               }

          }    

     }

}

class TickedDemo2

{

     public static void main(String[] args)

     {

          Ticket2 t = new Ticket2();

          Thread t1 = new Thread(t);    

          Thread t2 = new Thread(t);

          Thread t3 = new Thread(t);

          Thread t4 = new Thread(t);

          t1.start();

          t2.start();

          t3.start();

          t4.start();

     }

}

     

7,同步代码块:

        同步的前提:1,必须有两个以上的线程。2,多个线程都在使用一个锁
        同步的好处:解决了多线程的安全问题
        同步的判弊端:多个线程都需要判断锁,较为消耗资源

8,同步函数:  

如何找出安全问题?

     1,明确哪些代码是多线程运行的代码。

     2,明确共享数据。

     3,明确多线程中哪些共享数据被多条语句操作。

eg:

      

/**

需求:银行有一个金库,有两个储户分别存300元,每次存100,存3次

*/

class Bank

{

     private int Sum=0;

     Object obj = new Object();

     public synchronized void add(int n)//这里可以声明

     {

          //synchronized(obj)

//          {

               Sum+=n;

               try{Thread.sleep(10);}catch(Exception e){}

               System.out.println("SUM="+Sum);

//          }

     }

}


class Cus implements Runnable

{

     private Bank b = new Bank();

     public void run()//run方法中不可以抛出异常,只能处理。

     {

          for (int x=0;x<3;x++)

          {

               b.add(100);

          }

     }

}


class BankDemo

{

     public static void main(String[] args)

     {

          Cus c = new Cus();

          Thread t1 = new Thread(c);

          Thread t2 = new Thread(c);

          t1.start();

          t2.start();

     }

}  

9,同步函数的锁是this

         验证同步函数的锁是this:使用两个线程卖票,一个线程在同步代码块中,一个线程在函数中。
          eg:               

class Ticket2 implements Runnable

{

     private int tick = 500;

     Object obj = new Object();

     boolean flag = true;

     public void run()

     {

          if(flag)

          {

               while(true)

               {    

                    synchronized(obj)//代码块的锁是obj对象

                    {    

                         if(tick>0)

                         {

                              try{Thread.sleep(10);}catch(Exception e){}

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

                         }         

                    }    

               }

          }    


          else

          {

               while(true)

                    show();

          }

     }

     public synchronized void show()//同步函数的锁是this

     {

          if(tick>0)

          {

               try{Thread.sleep(10);}catch(Exception e){}

               System.out.println(Thread.currentThread().getName()+"show***********: "+tick--);//33

          }

     }

}

class ThisDemo

{

     public static void main(String[] args)

     {

          Ticket2 t = new Ticket2();

          Thread t1 = new Thread(t);    

          Thread t2 = new Thread(t);

          t1.start();//执行完这里,t1具备了资格,但是还没获得执行权,主线程接着把11、22执行完。这时候t2获得执行资格,并且获得执行权,这时只有33执行。因此下边让主线程停一会儿

          //try{Thread.sleep(10);}catch(Exception e){}//主线程sleep一会儿,线程0执行,主线程醒了,执行线程1

          t.flag = false;//11

          t2.start();//22

     }

}


10,静态同步函数的锁是Class对象

          静态进内存时,内存中没有对象,但是有该类对应的字节码文件对象。类名.class  该对象的类型是Class
          eg:             

class Ticket2 implements Runnable

{

     private static int tick = 500;

     boolean flag = true;

     public void run()

     {

          if(flag)

          {

               while(true)

               {    

                    synchronized(Ticket2.class)//

                    {    

                         if(tick>0)

                         {

                              try{Thread.sleep(10);}catch(Exception e){}

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

                         }         

                    }    

               }

          }    


          else

          {

               while(true)

                    show();

          }

     }


     public static synchronized void show()//静态同步函数的锁是该对象所在的字节码文件对象:类名.class,该对象的类型是Class

     {

          if(tick>0)

          {

               try{Thread.sleep(10);}catch(Exception e){}

               System.out.println(Thread.currentThread().getName()+"show***********: "+tick--);//33

          }

     }

}


class StaticDemo

{

     public static void main(String[] args)

     {

          Ticket2 t = new Ticket2();


          Thread t1 = new Thread(t);    

          Thread t2 = new Thread(t);

          t1.start();//执行完这里,t1具备了资格,但是还没获得执行权,主线程接着把11、22执行完。这时候t2获得执行资格,并且获得执行权,这时只有33执行。因此下边让主线程停一会儿

          try{Thread.sleep(10);}catch(Exception e){}//主线程sleep一会儿,线程0执行,主线程醒了,执行线程1

          t.flag = false;//11

          t2.start();//22


     }

}

11,单例设计模式:

        1,两中写法:
        俄汉式:
                        class Single

{

     private static final Single s = new Single();

     private Single(){}

     public static Single getInstance()

     {

          return s;

     }

}

懒汉式:

               class Singgle

{

     private static Single s = null;

     private Single(){}

     public static synchronized Single getInstance()

     {

          if(s==null)

          {

               synchronized(Single.class)

               {

                    if (s==null)

                    {

                         s=new Single();

                    }

               }

          }

          return s;

     }

}

2,俄汉式:多线程时不会安全问题

     懒汉式:用于延迟加载,多线程时会出现安全隐患,建立了多个对象,不符合单例设计模式的原则。

     如何解决懒汉式安全问题:可以加同步和同步函数可以解决,但是效率较低,可以用双重判断的形式解决低效问题,同步所属的对象时该类所属的字节码文字对象。


12,死锁:

               eg:          

class LockDemo implements Runnable

{

     private boolean flag = true;

     LockDemo(boolean flag)

     {

          this.flag=flag;

     }

    

     public void run()

     {

          if(flag)

          {

               while(true)

               {

                    synchronized(MyLock.locka)

                    {

                         System.out.println("if locka");

                         synchronized(MyLock.lockb)

                         {

                              System.out.println("if lockb");

                         }

                    }

               }

          }

          else

          {

               while(true)

               {

                    synchronized(MyLock.lockb)

                    {

                         System.out.println("if lockb");

                         synchronized(MyLock.locka)

                         {

                              System.out.println("if locka");

                         }

                    }

               }

          }

     }

}


class MyLock

{

     static Object locka = new Object();

     static Object lockb = new Object();

}

class DeadLockDemo

{

     public static void main(String[] args)

     {

          Thread t1 = new Thread(new LockDemo(true));

          Thread t2 = new Thread(new LockDemo(false));

          t1.start();

          t2.start();

     }

}

     

       

     

     

     

 

【上篇】
【下篇】

抱歉!评论已关闭.