黑马程序员——Java多线程

来源:互联网 发布:c语言中的sleep函数 编辑:程序博客网 时间:2024/05/18 02:59

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

进程与线程

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

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

一个进程中至少有一个线程。


多线程的运行可以看成是相互争夺cpu的执行权,这就是多线程的一个特征:随机性。谁抢到谁执行,至于执行多长,cpu说的算。


Java VM启动的时候会有一个进程java.exe。

该进程中至少一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称为主线程。

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


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

创建线程的两种方式:

继承Thread类

->步骤:

    |--定义类继承Thread。

    |--复写Thread类中的run方法。目的:将自定义代码存储在run方法,让线程运行。

    |--调用线程的start方法。 该方法两个作用:创建线程,调用run方法。

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. class Demo extends Thread{  
  2.     public void run(){  
  3.         for(int i = 0; i < 60; i++){  
  4.             System.out.println("demo run----" + i);  
  5.         }  
  6.     }  
  7. }  
  8. public class ThreadDemo {  
  9.   
  10.     public static void main(String[] args) {  
  11.         // TODO Auto-generated method stub  
  12.         Demo d = new Demo();  
  13.           
  14.         d.start();  //开启线程并执行该线程的run方法  
  15.         //d.run();  //仅仅是对象调用方法,而线程创建了,并没有运行  
  16.           
  17.         for(int i = 0; i < 60; i++){  
  18.             System.out.println("hello world----" + i);  
  19.         }  
  20.     }  
  21.   
  22. }  

实现Runnable接口

->步骤

    |--定义类实现接口Runnable接口。

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

    |--通过Thread类建立线程对象

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

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

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. class RunnableDemo implements Runnable{  
  2.   
  3.     private String name;  
  4.     public RunnableDemo(String name){  
  5.         this.name = name;  
  6.     }  
  7.     public void run() {  
  8.         // TODO Auto-generated method stub  
  9.         for(int i = 0; i < 5; i++){  
  10.             System.out.println(name + ":" + i);  
  11.         }  
  12.     }  
  13. }  
  14.   
  15. public class TestRunnable {  
  16.   
  17.     public static void main(String[] args) {  
  18.         // TODO Auto-generated method stub  
  19.         RunnableDemo r1 = new RunnableDemo("tom");  
  20.         RunnableDemo r2 = new RunnableDemo("jim");  
  21.           
  22.         Thread t1 = new Thread(r1);  
  23.         Thread t2 = new Thread(r2);  
  24.           
  25.         t1.start();  
  26.         t2.start();  
  27.     }  
  28. }  

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

自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去执行指定对象的run方法,就必须明确该run方法所属对象。


为什么要覆盖run方法?

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

线程都有自己默认的名字,通过getName获取线程名称。


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

实现方式好处:避免了单继承的局限性。在定义线程时,建立使用实现方式。

两种方式区别

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

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


多线程的运行方式导致其容易出现安全问题。

问题产生原因

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

解决方法

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

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. //java中通过:同步代码块  
  2. synchronized(对象)  
  3. {  
  4.     需要同步的代码  
  5. }  
同步的前提:

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

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

3. 必须保证同步中只能有一次线程执行。


优缺点

解决了多线程的安全问题;多个线程需要判断锁,较为消耗资源。


JDK1.5中提供了多线程升级解决方案。

将同步synchronized替换成现实lock操作,将object中的wait, notifyAll替换成立condition对象,该对象可以lock锁进行获取。


如何停止线程?

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


特殊情况:

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

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

Thread类提供该方法interrupt();

join:

当A线程执行到了B线程的join()方法时,A就会等待,等B线程执行完,A才会执行。join可以用来临时假死线程执行。


生产者消费者模型(同步代码块实现线程同步):

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class ProducerConsumer {  
  2.   
  3.     public static void main(String[] args) {  
  4.         // TODO Auto-generated method stub  
  5.         Resource r = new Resource();  
  6.         Producer pro = new Producer(r);  
  7.         Consumer con = new Consumer(r);  
  8.           
  9.         Thread t1 = new Thread(pro);  
  10.         Thread t2 = new Thread(con);  
  11.         t1.start();  
  12.         t2.start();  
  13.     }  
  14. }  
  15.   
  16. class Resource{  
  17.     private String name;  
  18.     private int count = 1;  
  19.     private boolean flag = false;  
  20.       
  21.     public synchronized void set(String name){  
  22.         while(flag)  
  23.             try {  
  24.                 wait();  
  25.             } catch (InterruptedException e) {  
  26.                 // TODO Auto-generated catch block  
  27.                 e.printStackTrace();  
  28.             }  
  29.         this.name = name + "..." + count++;  
  30.           
  31.         System.out.println(Thread.currentThread().getName() + "...生产者..." + this.name);  
  32.         flag = true;  
  33.         this.notifyAll();  
  34.     }  
  35.       
  36.     public synchronized void out(){  
  37.         while(!flag)  
  38.             try{  
  39.                 wait();  
  40.             } catch (InterruptedException e) {  
  41.                 // TODO Auto-generated catch block  
  42.                 e.printStackTrace();  
  43.             }  
  44.         System.out.println(Thread.currentThread().getName() + "...消费者..." + this.name);  
  45.         flag = false;  
  46.         this.notifyAll();  
  47.     }  
  48. }  
  49.   
  50. class Producer implements Runnable{  
  51.     private Resource res;  
  52.       
  53.     Producer(Resource res){  
  54.         this.res = res;  
  55.     }  
  56.       
  57.     public void run(){  
  58.         while(true){  
  59.             res.set("商品");  
  60.         }  
  61.     }  
  62. }  
  63.   
  64. class Consumer implements Runnable{  
  65.     private Resource res;  
  66.       
  67.     Consumer(Resource res){  
  68.         this.res = res;  
  69.     }  
  70.       
  71.     public void run(){  
  72.         while(true){  
  73.             res.out();  
  74.         }  
  75.     }  
  76. }  

0 0
原创粉丝点击