Android学习笔记——java线程基础

来源:互联网 发布:电源网络二合一防雷器 编辑:程序博客网 时间:2024/05/21 15:41

java线程

1、java线程的理解

线程就是程序执行代码块的过程:它会与各种状态,或者叫生命周期:创建、就绪(启动)、执行、阻塞、睡眠、结束(消亡),

上面这个顺序是不确定的

注意区分系统的进程与java的线程的区别,以及cpu时间片对java线程的影响

1.1 java虚拟机JVM是进程,在windows任务管理器中显示的java.exe 

1.2 一个普通java程序启动后,main方法所在的线程是主线程,这时java后台还有一个线程:负责垃圾回收,释放内存空间

1.3 多线程:即多个线程同时运行。

特点:并发执行,提高效率,消耗资源较大

1.4 java创建线程是通过调用底层系统的接口来实现的

1.5 在java中创建线程有两种方式:一种是继承Thread类,另外一种是实现Runable接口

1.6 通过继承Thread方法创建线程:

*继承Thread类

*创建此对象,并调用start()方法

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package thread;  
  2.   
  3. public class TestThreadCreat{  
  4.     public static void main(String[] args) {  
  5.         ThreadCreat  t1 = new ThreadCreat("threadCreat1");  
  6.         ThreadCreat  t2 = new ThreadCreat("threadCreat2");  
  7.         t1.start();  
  8.         t2.start();  
  9.     }  
  10.   
  11. }  
  12.   
  13. class ThreadCreat extends Thread{  
  14.     public ThreadCreat(String name){  
  15.         super(name);  
  16.     }  
  17.       
  18.     public void run(){  
  19.         int a = 1;  
  20.         while(a<=100){  
  21.             System.out.println(this.getName()+"__"+a++);  
  22.         }  
  23.     }  
  24. }  


1.7 通过实现Runable接口创建线程:

步骤:

*定义类实现Runnable接口

*覆盖Runnable接口中的run方法。将线程要运行的代码存放在该run方法中。

 *通过Thread类建立线程对象。

*将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。

    为什么要将Runnable接口的子类对象传递给Thread的构造函数。

    因为,自定义的run方法所属的对象是Runnable接口的子类对象。

    所以要让线程去指定指定对象的run方法。就必须明确该run方法所属对象。

*调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。


[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package thread;  
  2.   
  3. public class TestRunnableCreate {  
  4.   
  5.     public static void main(String[] args) {  
  6.         RunnableCreate runnableCreate1 = new RunnableCreate();  
  7.         RunnableCreate runnableCreate2 = new RunnableCreate();  
  8.         new Thread(runnableCreate1).start();  
  9.         new Thread(runnableCreate1).start();  
  10.     }  
  11.   
  12.   
  13. }  
  14.   
  15. class RunnableCreate implements Runnable {  
  16.     
  17.     public void run(){  
  18.         int a = 1;  
  19.         while(a<=100){  
  20.             System.out.println(Thread.currentThread().getName()+"__"+a++);  
  21.         }  
  22.     }  
  23. }  


2 多线程的安全问题:当多个线程同时对相同的资源进行操作时,就有可能导致访问的资源不准确,这种情况就称之为线程安全问题。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package thread;  
  2. /* 
  3.  * 不安全的多线程售票,可能出现负票 
  4.  */  
  5.   
  6. public class TestThreadDanger {  
  7.   
  8.     public static void main(String[] args) {  
  9.          Ticket t1 = new Ticket();  
  10.          new Thread(t1,"TicketSaleMan1").start();  
  11.          new Thread(t1,"TicketSaleMan2").start();  
  12.          new Thread(t1,"TicketSaleMan3").start();  
  13.          new Thread(t1,"TicketSaleMan4").start();  
  14.     }  
  15.   
  16. }  
  17.   
  18. class Ticket implements Runnable {  
  19.     private int tick = 100;  
  20.     public void run(){  
  21.         while(true){  
  22.             if(tick>0){  
  23.                 try{Thread.sleep(20);}catch(Exception e){}  
  24.                 System.out.println(Thread.currentThread().getName()+"__sale:"+tick--);  
  25.             }  
  26.             else{  
  27.                 break;  
  28.             }  
  29.         }  
  30.     }  
  31. }  


2.1 java中通过同步这个概念来解决线程安全问题

即,将多个线程共通操作的资源进行访问控制(锁/锁旗标),在某一个时刻只能一天线程进行操作。关键字是:syschronized

同步的前提:*两个及两个以上线程

    *多个线程的访问控制使用同一个锁

2.2 java中同步有 种实现方式:同步代码块,同步函数(静态同步函数和非静态同步函数)

2.2.1 同步代码块:

将多线程共通执行的代码块放到同步代码块中执行,这样就可以通过同步代码块的锁进行访问控制。

如果一个线程先持有同步代码块的锁,则在它释放这个锁之前,其它现在只能在外面等待

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package thread;  
  2.   
  3. /* 
  4.  *增加同步代码块后,这个程序是线程安全的 
  5.  */  
  6.   
  7. public class TestThreadDanger {  
  8.   
  9.     public static void main(String[] args) {  
  10.         Ticket t1 = new Ticket();  
  11.         new Thread(t1, "TicketSaleMan1").start();  
  12.         new Thread(t1, "TicketSaleMan2").start();  
  13.         new Thread(t1, "TicketSaleMan3").start();  
  14.         new Thread(t1, "TicketSaleMan4").start();  
  15.     }  
  16.   
  17. }  
  18.   
  19. class Ticket implements Runnable {  
  20.   
  21.     private int tick = 100;  
  22.     Object obj = new Object();  
  23.   
  24.     public void run() {  
  25.         while (true) {  
  26.             //同步代码块,将同步代码放入同步代码块中执行  
  27.             synchronized (obj) {// obj为自己创建的锁旗标  
  28.                 if (tick > 0) {  
  29.                     try {  
  30.                         Thread.sleep(20);  
  31.                     }  
  32.                     catch (Exception e) {  
  33.                     }  
  34.                     System.out.println(Thread.currentThread().getName() + "__sale:" + tick--);  
  35.                 }  
  36.   
  37.                 else {  
  38.                     break;  
  39.                 }  
  40.             }  
  41.         }  
  42.     }  
  43. }  

2.2.2 同步函数:

将多线程并发访问的代码封装到函数里面,然后在函数声明的时候加上synchronized,进行同步访问控制。

同步函数的锁是this,即本对象

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package thread;  
  2.   
  3. /* 
  4.  * 同步函数 
  5.  */  
  6.   
  7. public class TestThreadDanger {  
  8.   
  9.     public static void main(String[] args) {  
  10.         Ticket t1 = new Ticket();  
  11.         new Thread(t1, "TicketSaleMan1").start();  
  12.         new Thread(t1, "TicketSaleMan2").start();  
  13.         new Thread(t1, "TicketSaleMan3").start();  
  14.         new Thread(t1, "TicketSaleMan4").start();  
  15.     }  
  16.   
  17. }  
  18.   
  19. class Ticket implements Runnable {  
  20.   
  21.     private int tick = 100;  
  22.     Object obj = new Object();  
  23.     boolean haveTicket = true;  
  24.     public void run() {  
  25.         while (true) {  
  26.             if (haveTicket)   
  27.                 saleTicket();  
  28.             else  
  29.                 break;  
  30.         }  
  31.     }  
  32.       
  33.       
  34.     public synchronized void saleTicket(){  
  35.         if (tick > 0) {  
  36.             try {Thread.sleep(20);}catch (Exception e) {}  
  37.             System.out.println(Thread.currentThread().getName() + "__sale:" + tick--);  
  38.         }else{  
  39.             haveTicket = false;  
  40.         }  
  41.     }  
  42.       
  43.       
  44. }  

2.2.3 静态同步函数

静态同步函数的锁是该类的字节码文件对象

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class Ticket implements Runnable  
  2. {  
  3.     private static  int tick = 100;  
  4.     //Object obj = new Object();  
  5.     boolean flag = true;  
  6.     public  void run()  
  7.     {  
  8.         if(flag)  
  9.         {  
  10.             while(true)  
  11.             {  
  12.                 synchronized(Ticket.class)  
  13.                 {  
  14.                     if(tick>0)  
  15.                     {  
  16.                         try{Thread.sleep(10);}catch(Exception e){}  
  17.                         System.out.println(Thread.currentThread().getName()+"....code : "+ tick--);  
  18.                     }  
  19.                 }  
  20.             }  
  21.         }  
  22.         else  
  23.             while(true)  
  24.                 show();  
  25.     }  
  26.     public static synchronized void show()  
  27.     {  
  28.         if(tick>0)  
  29.         {  
  30.             try{Thread.sleep(10);}catch(Exception e){}  
  31.             System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--);  
  32.         }  
  33.     }  
  34. }  
  35.   
  36.   
  37. class  StaticMethodDemo  
  38. {  
  39.     public static void main(String[] args)   
  40.     {  
  41.   
  42.         Ticket t = new Ticket();  
  43.   
  44.         Thread t1 = new Thread(t);  
  45.         Thread t2 = new Thread(t);  
  46.         t1.start();  
  47.         try{Thread.sleep(10);}catch(Exception e){}  
  48.         t.flag = false;  
  49.         t2.start();  
  50.   
  51.   
  52.     }  
  53. }  

2.3 使用静态同步函数实现单例设计模式的懒汉式

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * 懒汉式,或者延迟加载,当需要的时候才创建这个类 
  3.  * 懒汉式要注意的是线程安全问题 
  4.  */  
  5. class SingletonDelay{  
  6.     private SingletonDelay(){};  
  7.     private static SingletonDelay sin = null;  
  8.     public static SingletonDelay getInstence(){  
  9.         if(sin == null){//双重判断的目的是为了减少锁的比较次数,提高效率  
  10.             synchronized(SingletonDelay.class){//静态方法的锁必须用类的字节码对象  
  11.                 if(sin==null){  
  12.                     sin = new SingletonDelay();  
  13.                 }  
  14.             }  
  15.         }  
  16.         return sin;  
  17.     }  
  18. }  

2.4 死锁

死锁,当多个线程之间并发执行,出现线程无限等待的现象称为死锁。

死锁产生的可能原因:

--A线程持有锁1,A线程现在需要锁2里面被控制的资源;B线程持有锁2,B线程现在需要锁1里面被控制的资源。因此线程A与B陷入相互需要对方资源,恶性循环中。

--嵌套锁:锁里面有锁

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2. 死锁。 
  3. 同步中嵌套同步。 
  4.  
  5. */  
  6.   
  7. class Ticket implements Runnable  
  8. {  
  9.     private  int tick = 1000;  
  10.     Object obj = new Object();  
  11.     boolean flag = true;  
  12.     public  void run()  
  13.     {  
  14.         if(flag)  
  15.         {  
  16.             while(true)  
  17.             {  
  18.                 synchronized(obj)  
  19.                 {  
  20.                     show();  
  21.                 }  
  22.             }  
  23.         }  
  24.         else  
  25.             while(true)  
  26.                 show();  
  27.     }  
  28.     public synchronized void show()//this  
  29.     {  
  30.         synchronized(obj)  
  31.         {  
  32.             if(tick>0)  
  33.             {  
  34.                 try{Thread.sleep(10);}catch(Exception e){}  
  35.                 System.out.println(Thread.currentThread().getName()+"....code : "+ tick--);  
  36.             }  
  37.         }  
  38.     }  
  39. }  
  40.   
  41.   
  42. class  DeadLockDemo  
  43. {  
  44.     public static void main(String[] args)   
  45.     {  
  46.   
  47.         Ticket t = new Ticket();  
  48.   
  49.         Thread t1 = new Thread(t);  
  50.         Thread t2 = new Thread(t);  
  51.         t1.start();  
  52.         try{Thread.sleep(10);}catch(Exception e){}  
  53.         t.flag = false;  
  54.         t2.start();  
  55.   
  56.   
  57.     }  
  58. }  


 2.5 多线程通信

多线程通信:等待/唤醒机制.即多个线程并发访问相同资源时,分工明确的线程,一个负责生产,一个负责消费,那么在这种情况下,

资源对于它们来时就是一个需要同步访问控制的东西。资源没有了,消费者就要通知生产者生产,消费者自己等待。生产者生产好

资源了,就应该通知消费者消费,自己等待。这就是多线程通信。

2.5.1 等待唤醒机制

在jdk1.5之前等待唤醒机制是通过在同步块里面使用方法:wait() :使线程进入冻结状态,,notify():唤醒线程池中排序的第一个线程,

notifyAll()唤醒线程池中所有等待的线程。

线程通信示例:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class ProducerConsumerDemo   
  2. {  
  3.     public static void main(String[] args)   
  4.     {  
  5.         Resource r = new Resource();  
  6.   
  7.         Producer pro = new Producer(r);  
  8.         Consumer con = new Consumer(r);  
  9.   
  10.         Thread t1 = new Thread(pro);  
  11.         Thread t2 = new Thread(pro);  
  12.         Thread t3 = new Thread(con);  
  13.         Thread t4 = new Thread(con);  
  14.   
  15.         t1.start();  
  16.         t2.start();  
  17.         t3.start();  
  18.         t4.start();  
  19.   
  20.     }  
  21. }  
  22.   
  23. /* 
  24. 对于多个生产者和消费者。 
  25. 为什么要定义while判断标记。 
  26. 原因:让被唤醒的线程再一次判断标记。 
  27.  
  28.  
  29. 为什么定义notifyAll, 
  30. 因为需要唤醒对方线程。 
  31. 因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。 
  32.  
  33. */  
  34.   
  35.   
  36. class Resource  
  37. {  
  38.     private String name;  
  39.     private int count = 1;  
  40.     private boolean flag = false;  
  41.             //  t1    t2  
  42.     public synchronized void set(String name)  
  43.     {  
  44.         while(flag)  
  45.             try{this.wait();}catch(Exception e){}//t1(放弃资格)  t2(获取资格)  
  46.         this.name = name+"--"+count++;  
  47.   
  48.         System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);  
  49.         flag = true;  
  50.         this.notifyAll();  
  51.     }  
  52.   
  53.   
  54.     //  t3   t4    
  55.     public synchronized void out()  
  56.     {  
  57.         while(!flag)  
  58.             try{wait();}catch(Exception e){}//t3(放弃资格) t4(放弃资格)  
  59.         System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);  
  60.         flag = false;  
  61.         this.notifyAll();  
  62.     }  
  63. }  
  64.   
  65. class Producer implements Runnable  
  66. {  
  67.     private Resource res;  
  68.   
  69.     Producer(Resource res)  
  70.     {  
  71.         this.res = res;  
  72.     }  
  73.     public void run()  
  74.     {  
  75.         while(true)  
  76.         {  
  77.             res.set("+商品+");  
  78.         }  
  79.     }  
  80. }  
  81.   
  82. class Consumer implements Runnable  
  83. {  
  84.     private Resource res;  
  85.   
  86.     Consumer(Resource res)  
  87.     {  
  88.         this.res = res;  
  89.     }  
  90.     public void run()  
  91.     {  
  92.         while(true)  
  93.         {  
  94.             res.out();  
  95.         }  
  96.     }  
  97. }  

2.5.2 JDK1.5对线程锁的升级

在JDK 1.5中,提供了改进synchronized的升级解决方案。将同步synchronized替换为显式的Lock操作,将Object中的wait,notify,notifyAll替换成Condition对象,该对象可对Lock锁进行获取。wait,notify,notifyAll这些方法都定义在Object中,是因为这些方法操作同步中的线程时,都必须表示自己所操作的线程的锁,就是说,等待和唤醒的必须是同一把锁。不可对不同锁中的线程进行唤醒。所以这就使得程序是不良的,因此,通过对锁机制的改良,使得程序得到优化。


[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2. 线程间通信: 
  3.  
  4. 等待唤醒机制:升级版 
  5.  
  6. 生产者消费者  多个 
  7.  
  8. */  
  9. import java.util.concurrent.locks.*;  
  10.   
  11. class ProducerConsumerDemo{  
  12.     public static void main(String[] args){  
  13.         Resouse r = new Resouse();  
  14.         Producer p = new Producer(r);  
  15.         Consumer c = new Consumer(r);  
  16.         Thread t1 = new Thread(p);  
  17.         Thread t2 = new Thread(c);  
  18.         Thread t3 = new Thread(p);  
  19.         Thread t4 = new Thread(c);  
  20.         t1.start();  
  21.         t2.start();  
  22.         t3.start();  
  23.         t4.start();  
  24.     }  
  25. }  
  26.   
  27. class Resouse{  
  28.     private String name;  
  29.     private int count = 1;  
  30.     private boolean flag =  false;   
  31.     private Lock lock = new ReentrantLock();  
  32.     private Condition condition_P = lock.newCondition();  
  33.     private Condition condition_C = lock.newCondition();  
  34. //要唤醒全部,否则都可能处于冻结状态,那么程序就会停止。这和死锁有区别的。  
  35.     public void set(String name)throws InterruptedException{  
  36.         lock.lock();  
  37.         try{  
  38.             while(flag)//循环判断,防止都冻结状态  
  39.                 condition_P.await();  
  40.             this.name = name + "--" + count++;  
  41.             System.out.println(Thread.currentThread().getName() + "..生成者--" + this.name);  
  42.             flag = true;  
  43.             condition_C.signal();  
  44.         }finally{  
  45.             lock.unlock();//释放锁的机制一定要执行  
  46.         }         
  47.     }  
  48.     public void out()throws InterruptedException{  
  49.         lock.lock();  
  50.         try{  
  51.             while(!flag)//循环判断,防止都冻结状态  
  52.                 condition_C.await();  
  53.             System.out.println(Thread.currentThread().getName() + "..消费者." + this.name);  
  54.             flag = false;  
  55.             condition_P.signal();//唤醒全部  
  56.         }finally{  
  57.             lock.unlock();  
  58.         }  
  59.     }  
  60. }  
  61.   
  62. class Producer implements Runnable{  
  63.     private Resouse r;  
  64.     Producer(Resouse r){  
  65.         this.r = r;  
  66.     }  
  67.     public void run(){  
  68.         while(true){  
  69.             try{  
  70.                 r.set("--商品--");  
  71.             }catch (InterruptedException e){}  
  72.         }  
  73.     }  
  74. }  
  75.   
  76. class Consumer implements Runnable{  
  77.     private Resouse r;  
  78.     Consumer(Resouse r){  
  79.         this.r = r;  
  80.     }  
  81.     public void run(){  
  82.         while(true){  
  83.             try{  
  84.                 r.out();  
  85.             }catch (InterruptedException e){}  
  86.         }  
  87.     }  
  88. }  

2.6 停止线程

从JDK1.5自后线程里面的方法stop()显示已经过时,那么我们怎么停止线程呢?肯定是结束run()方法呀,怎么结束run()方法呢?一般情况下,run方法里面就有while循环,我们结束循环就可以了。

通过标记结束循环:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class StopThread implements Runnable{  
  2.     private boolean flag = true;  
  3.     public synchronized void run(){  
  4.         while (flag){  
  5.             try{  
  6.                 wait();  
  7.             }catch (InterruptedException e) {  
  8.                 System.out.println(Thread.currentThread().getName() + "----Exception");  
  9.                 flag = false;  
  10.             }  
  11.             System.out.println(Thread.currentThread().getName() + "----run");  
  12.         }  
  13.     }  
  14.     public void changeFlag(){  
  15.         flag = false;  
  16.     }  
  17. }  
  18.   
  19. class  StopThreadDemo{  
  20.     public static void main(String[] args) {  
  21.         StopThread st = new StopThread();  
  22.   
  23.         Thread t1 = new Thread(st);  
  24.         Thread t2 = new Thread(st);  
  25.           
  26.         t1.start();  
  27.         t2.start();  
  28.   
  29.         int n = 0;  
  30.         while (true){  
  31.             if (n++ == 60){  
  32.                 st.changeFlag();  
  33.                 break;  
  34.             }  
  35.             System.out.println("Hello World!");  
  36.         }  
  37.     }  
  38. }  

上面有特殊情况:当线程处于冻结状态,就不会读取标记,那么线程就不会结束

因此我们必须使用Thread类里面提供的interrupt()方法,来中断线程,但不会让它死掉,会让线程脱了冻结状态,恢复到运行状态,再去判断标记,然后结束循环,最终跳出run方法。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class StopThread implements Runnable{  
  2.     private boolean flag = true;  
  3.     public synchronized void run(){  
  4.         while (flag){  
  5.             try{  
  6.                 wait();  
  7.             }catch (InterruptedException e){  
  8.                 System.out.println(Thread.currentThread().getName() + "----Exception");  
  9.                 flag = false;  
  10.             }  
  11.             System.out.println(Thread.currentThread().getName() + "----run");  
  12.         }  
  13.     }  
  14. }  
  15.   
  16. class  StopThreadDemo{  
  17.     public static void main(String[] args){  
  18.         StopThread st = new StopThread();  
  19.         Thread t1 = new Thread(st);  
  20.         Thread t2 = new Thread(st);       
  21.         t1.start();  
  22.         t2.start();  
  23.         int n = 0;  
  24.         while (true){  
  25.             if (n++ == 60){  
  26.                 t1.interrupt();  
  27.                 t2.interrupt();  
  28.                 break;  
  29.             }  
  30.             System.out.println("Hello World!");  
  31.         }  
  32.     }  
  33. }  

2.7 守护线程

在线程创建后,在启动以前,调用方法setDeamon(),可以将一个线程标记为守护线程。如果这个线程结束,则java虚拟机也会结束。


2.8  join线程

 当A线程执行到B线程方法时,A线程就会等待,B线程都执行完,A才会执行。join可用来临时加入线程执行。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class Demo implements Runnable{  
  2.     public void run(){  
  3.         for(int x=0;x<90;x++){  
  4.             System.out.println(Thread.currentThread().getName() + "----run" + x);  
  5.         }  
  6.     }  
  7. }  
  8.   
  9. class  JoinDemo{  
  10.     public static void main(String[] args)throws Exception{  
  11.         Demo d = new Demo();  
  12.         Thread t1 = new Thread(d);  
  13.         Thread t2 = new Thread(d);  
  14.         t1.start();       
  15.         t2.start();  
  16.         t1.join();//等t1执行完了,主线程才从冻结状态恢复,和t2抢执行权。t2执不执行完都无所谓。  
  17.         int n = 0;  
  18.         for(int x=0;x<80;x++){  
  19.             System.out.println(Thread.currentThread().getName() + "----main" + x);  
  20.         }  
  21.         System.out.println("Over");  
  22.     }  
  23. }  

2.9 其它方法:

设置线程优先级:可通过setPriority()设定,如:setPriority(Thread.MAX_PRIORITY)设优先级为最大。

不执行这个线程,跳到其它线程:yield() 通过这个方法,可稍微减少线程执行频率,达到线程都有机会平均被执行的效果。


0 0
原创粉丝点击