关于线程的总结


进程:是一个正在执行中的程序。 每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。

 线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行。一个进程中至少有一个线程。

JavaVM  启动的时候会有一个进程java.exe.

 该进程中至少一个线程负责java程序的执行。

而且这个线程运行的代码存在于main方法中。

该线程称之为主线程。

 扩展:其实更细节说明jvm,jvm启动不止一个线程,还有负责垃圾回收机制的线程。

1,如何在自定义的代码中,自定义一个线程呢?

创建线程的方法有两种:

 第一种方式:继承Thread类。

步骤:

1,定义类继承Thread。

2,复写Thread类中的run方法。

3,调用线程的start方法, 该方法两个作用:启动线程,调用run方法。

 示例代码如下:

[html]  view plain copy
  1. class Demo extends Thread  
  2. {  
  3.     public void run()  
  4.     {  
  5.         for(int x=0; x<60; x++)  
  6.             System.out.println("demo run----"+x);  
  7.     }  
  8. }  
  9.   
  10.   
  11. class ThreadDemo   
  12. {  
  13.     public static void main(String[] args)   
  14.     {  
  15.         //for(int x=0; x<4000; x++)  
  16.         //System.out.println("Hello World!");  
  17.   
  18.         Demo d = new Demo();//创建好一个线程。  
  19.         //d.start();//开启线程并执行该线程的run方法。  
  20.         d.run();//仅仅是对象调用方法。而线程创建了,并没有运行。  
  21.   
  22.           
  23.         for(int x=0; x<60; x++)  
  24.             System.out.println("Hello World!--"+x);  
  25.             }  
  26. }  

为什么要覆盖run方法呢?

Thread类用于描述线程。

该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。

也就是说Thread类中的run方法,用于存储线程要运行的代码。

第二种方法:

Java给我们提供了一个规则。Runnable接口。

如果自定义类不继承Thread,也可以实现Runnable接口。并将多线程要运行的代码存放在Runnable的run方法中。所以也可以实现Runnable接口来定义线程。

步骤:

1,定义了实现Runnable接口。

2,覆盖接口的run方法。将多线程要运行的代码存入其中。

3,创建Thread类的对象(创建线程),并将Runnable接口的子类对象作为参数传递给Thread的构造函数。

    为什么要传递?因为线程要运行的代码都在Runnable子类的run方法中存储。所以要将该run方法所属的对象

    传递给Thread。让Thread线程去使用该对象调用其run方法。

4,调用Thread对象的start方法。开启线程。程序如下:

 示例代码如下:

[html]  view plain copy
  1. package xuexi1;  
  2.   
  3. public class ThreadDemo1 {  
  4.   
  5.     /**  
  6.      * @param args  
  7.      */  
  8.     public static void main(String[] args) {  
  9.         // TODO Auto-generated method stub  
  10.          ticket1 t=new ticket1();  
  11.          Thread t1=new Thread(t);  
  12.          Thread t2=new Thread(t);  
  13.          Thread t3=new Thread(t);  
  14.          Thread t4=new Thread(t);  
  15.          t1.start();  
  16.          t2.start();  
  17.          t3.start();  
  18.          t4.start();  
  19.     }  
  20.   
  21. }  
  22. class ticket1 implements Runnable{  
  23.     private static int ticket=100;  
  24.   
  25.     @Override  
  26.     public void run() {  
  27.         // TODO Auto-generated method stub  
  28.         while(true){  
  29.             synchronized(new Object()){  
  30.             if(ticket>0){  
  31.                 System.out.println(Thread.currentThread().getName()+"......"+ticket--);  
  32.             }  
  33.             }  
  34.         }  
  35.     }  
  36.       
  37. }  

实现方式和继承方式有什么区别呢?

继承Thread:  线程代码存放Thread子类run方法中。

实现Runnable:线程代码存在接口的子类的run方法。

因为避免了单继承的局限性,所以创建线程建议使用第二种方式。

为什么运行结果每一次都不同?

因为多个线程都获取cpu的执行权。cpu执行到谁,谁就运行。明确一点,在某一个时刻,只能有一个程序在运行(多核除外)。cpu在做着快速的切换,以达到看上去是同时运行的效果。我们可以形象把多线程的运行行为在互相抢夺cpu的执行权。这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多长,cpu说的算。

多线程具备随机性。因为是由cpu不断的快速切换造成的。就有可能会产生多线程的安全问题。

问题的产生的原因:

1,多线程代码中有操作共享数据。

2,多条语句操作该共享数据。

有一个线程对多条操作共享数据的代码执行的一部分。还没有执行完,另一个线程开始参与执行。

就会发生数据错误。

解决方法:

当一个线程在执行多条操作共享数据代码时,其他线程即使获取了执行权,也不可以参与操作。

 java就对这种解决方式提供了专业的代码同步。

同步的原理:就是将部分操作功能数据的代码进行加锁。

同步使用的前提:

    1,必须是两个或者两个以上的线程。

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

    这是才可以称为这些线程被同步了。

同步的示例代码:

[html]  view plain copy
  1. package xuexi1;  
  2.   
  3. public class InputOutputDemo2 {  
  4.   
  5.     /**  
  6.      * @param args  
  7.      */  
  8.     public static void main(String[] args) {  
  9.         // TODO Auto-generated method stub  
  10.         Resource1 r1=new Resource1();  
  11.         new Thread(new Input1(r1)).start();  
  12.         new Thread(new Output1(r1)).start();  
  13.         new Thread(new Input1(r1)).start();  
  14.         new Thread(new Output1(r1)).start();  
  15.     }  
  16.   
  17. }  
  18. class Resource1{  
  19.     private String name;  
  20.     private String sex;  
  21.     boolean flag=false;  
  22.     public synchronized void set(String name,String sex){  
  23.         if(flag){  
  24.             try{      
  25.                 this.wait();  
  26.                }  
  27.             catch(Exception e){  
  28.                 System.out.println(e.toString());  
  29.                }  
  30.            }  
  31.         this.name=name;  
  32.         this.sex=sex;  
  33.         flag=true;  
  34.         this.notifyAll();  
  35.     }  
  36.     public synchronized void get(){  
  37.         if(!flag){  
  38.             try{  
  39.                 this.wait();  
  40.             }  
  41.             catch(Exception e){  
  42.                 e.printStackTrace();  
  43.             }  
  44.         }  
  45.         else{  
  46.              System.out.println(this.name+"....."+this.sex+"***"+Thread.currentThread().getName());  
  47.              flag=false;  
  48.              this.notifyAll();  
  49.         }  
  50.     }  
  51. }  
  52. class Input1 implements Runnable{  
  53.     Resource1 res;  
  54.       
  55.     Input1(Resource1 res){  
  56.         this.res=res;  
  57.     }  
  58.     @Override  
  59.     public void run(){  
  60.         int i=0;  
  61.         while(true){  
  62.             if(i==0)  
  63.                 res.set("123","456");  
  64.             else if(i==1){  
  65.                 res.set("ggggg","asdf");  
  66.             }  
  67.             i=(i+1)%2;  
  68.         }  
  69.     }  
  70. }  
  71. class Output1 implements Runnable{  
  72.     Resource1 res;  
  73.     Output1(Resource1 res){  
  74.         this.res=res;  
  75.     }  
  76.        public void run() {  
  77.            while(true){  
  78.                res.get();   
  79.            }  
  80.         }  
  81.       
  82. }  

1.5版本后用lock()和unlock()来同步。并且用condition来激活和冻结指定的这样就避免了死锁或者用notifyAll()来激活所用的线程。示例代码如下:

[html]  view plain copy
  1. package xuexi1;  
  2.   
  3. import java.util.concurrent.locks.Condition;  
  4. import java.util.concurrent.locks.Lock;  
  5. import java.util.concurrent.locks.ReentrantLock;  
  6. import java.util.concurrent.locks.ReentrantReadWriteLock;  
  7.   
  8. public class ProductConsumerDemo1 {  
  9.   
  10.     /**  
  11.      * @param args  
  12.      */  
  13.     public static void main(String[] args) {  
  14.         // TODO Auto-generated method stub  
  15.         Resource4 res =new Resource4();  
  16.         productor4 pro=new productor4(res);  
  17.         consumor4 con=new consumor4(res);  
  18.         new Thread(pro).start();     
  19.         new Thread(pro).start();  
  20.         new Thread(con).start();  
  21.         new Thread(con).start();  
  22.           
  23.     }  
  24.   
  25. }  
  26. class Resource4{  
  27.     private int count=0;  
  28.     private String name ;  
  29.     private boolean flag;  
  30.     private Lock lock=new ReentrantLock();  
  31.     private Condition pro=lock.newCondition();  
  32.     private Condition con=lock.newCondition();  
  33.     public void produce(String name) throws InterruptedException{  
  34.         lock.lock();  
  35.         try{  
  36.         while(flag)   
  37.                 pro.await();      
  38.         this.name=name+count++;  
  39.         System.out.println("producer..."+this.name+".."+Thread.currentThread().getName());  
  40.         flag=true;  
  41.         con.signal();  
  42.         }finally{  
  43.             lock.unlock();  
  44.         }  
  45.     }  
  46.     public void consum(){  
  47.         lock.lock();  
  48.         try{  
  49.             while(!flag){  
  50.                 try {  
  51.                     con.await();  
  52.                 } catch (InterruptedException e) {  
  53.                     // TODO Auto-generated catch block  
  54.                     e.printStackTrace();  
  55.                 }  
  56.             }  
  57.             System.out.println("consumor,,,,,,,,,,,,,"+this.name+".."+Thread.currentThread().getName());  
  58.             flag=false;  
  59.             pro.signal();  
  60.               
  61.               
  62.         }finally{  
  63.             lock.unlock();  
  64.         }  
  65.           
  66.     }  
  67. }  
  68. class productor4 implements Runnable{  
  69.     private int i=0;  
  70.     private Resource4 res;  
  71.     productor4(Resource4 res){  
  72.         this.res=res;  
  73.     }  
  74.       
  75.      public void run() {  
  76.         while(true){  
  77.               
  78.                 try {  
  79.                     if(i==0)  
  80.                          res.produce("123");  
  81.                     else if(i==1)             
  82.                          res.produce("asddff");  
  83.                     i=(i+1)%2;                  
  84.                 } catch (InterruptedException e) {  
  85.                     // TODO Auto-generated catch block  
  86.                     e.printStackTrace();  
  87.                 }                             
  88.           }  
  89.        }  
  90.     }  
  91.       
  92.   
  93. class consumor4 implements Runnable{  
  94.     private Resource4 res;  
  95.     consumor4(Resource4 res){  
  96.         this.res=res;  
  97.     }  
  98.       
  99.     public void run(){  
  100.        while(true){  
  101.             res.consum();  
  102.         }  
  103.     }  
  104. }  

如何停止线程?

只有一种,run方法结束。

开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,也就是线程结束。

 特殊情况:

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

Thread类提供该方法 interrupt()方法来解决这一问题。如下面的代码:

[html]  view plain copy
  1. class StopThread implements Runnable  
  2. {  
  3.     private boolean flag =true;  
  4.     public  void run()  
  5.     {  
  6.         while(flag)  
  7.         {  
  8.               
  9.             System.out.println(Thread.currentThread().getName()+"....run");  
  10.         }  
  11.     }  
  12.     public void changeFlag()  
  13.     {  
  14.         flag = false;  
  15.     }  
  16. }  
  17.   
  18. class  StopThreadDemo  
  19. {  
  20.     public static void main(String[] args)   
  21.     {  
  22.         StopThread st = new StopThread();  
  23.           
  24.         Thread t1 = new Thread(st);  
  25.         Thread t2 = new Thread(st);  
  26.   
  27.   
  28.         t1.setDaemon(true);  
  29.         t2.setDaemon(true);  
  30.         t1.start();  
  31.         t2.start();  
  32.   
  33.         int num = 0;  
  34.   
  35.         while(true)  
  36.         {  
  37.             if(num++ == 60)  
  38.             {  
  39.                 st.changeFlag();  
  40.                 t1.interrupt();  
  41.                 t2.interrupt();  
  42.                 break;  
  43.             }  
  44.             System.out.println(Thread.currentThread().getName()+"......."+num);  
  45.         }  
  46.         System.out.println("over");  
  47.     }  
  48. }  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值