黑马程序员_6_简单创建多线程

                                     黑马程序员——简单创建多线程

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



多线程:在一个进程中有多个执行路径。
            进程是正在运行的应用程序作为一个进程,进程中一个执行路径是一个线程<负责代码执行>。
     说到这里很多人都会有一个疑问,线程是负责代码的执行,有时我们没创建线程,为什么代码一样可以执行呢?
            因为一个java的应用程序,至少有俩个线程,都是jvm创建的,一个是主线程,负责main的代码执行,同时还会创建一个垃圾回收器线程, 负责垃圾回收。

那么多线程的优点:
             1、可以在进程中同时执行多个任务代码。
               2、提高了资源的利用率。而不是效率...
多线程的弊端:
             1、增加了cpu的负担。
             2、降低了一个进程线程的执行概率,
             2、会出现线程安全问题。
             3、引发了死锁问题。

说了这么多了,那怎么自定义线程呢?
        sun公司给我们提供了一个线程基类Thread
        步骤1:自定义一个类继承Thread
               2:重写Thread里面run()方法,把自定义线程的代码放入run()方法中。
               3:创建线程对象,调用start方法开启线程任务,线程一旦开启就会自动调用run()方法执行里面的代码。

注意:run方法不能直接的调用,如果直接调用了run方法,那么没有开启一个新的线程 ,只是相当于调用另一个普通方法而已。一定要调用start方法开启一个线程,线程启动时就回去执行run方法的代码了。  

说了这么多了,那我们就来自定义一个多线程吧。
    
    
  1. class MyThread extends Thread{//声明一个类继承线程Thread类
  2. //重写run()把自定义线程执行的代码放入其中
  3. public void run(){
  4. for(int i=0;i<1000;i++){
  5. System.out.println("自定义线程执行了..."+i);
  6. }
  7. }
  8. }
  9. class Demo1{
  10. public static void main(String[] args){
  11. //创建线程对象
  12. MyThread my = new MyThread();
  13. //调用start方法开启线程。
  14. my.start();
  15. }
  16. }
当我们再来使用多线程模拟车站售票时,却发现事没那么简单。

    
    
  1. package cn.chen.thread;
  2. //模拟车站卖票。。
  3. class SaleTicket extends Thread{
  4. //必须用静态修饰,因为保证3个窗口使用同一份数据。非静态成员变量会在每创建一个对象维护一份。
  5. static int tickets=50;
  6. //使用锁对象的时候,多个线程必须是使用同一个锁对象。
  7. static Object o = new Object();
  8. public SaleTicket(String name){
  9. super(name);
  10. }
  11. public void run(){
  12. while(true){
  13. //锁对象是任意的对象,但必须保证同一份...
  14. synchronized (o){
  15. if(tickets>0){
  16. System.out.println(Thread.currentThread().getName()+"卖出第"+tickets+"张票");
  17. tickets--;
  18. }else{
  19. System.out.println("票已经售馨...");
  20. break;
  21. }
  22. }
  23. }
  24. }
  25. }
  26. public class Demo3 {
  27. public static void main(String[] args) {
  28. //创建线程对象
  29. SaleTicket st1 = new SaleTicket("一号窗口");
  30. SaleTicket st2 = new SaleTicket("二号窗口");
  31. SaleTicket st3 = new SaleTicket("三号窗口");
  32. //开启线程
  33. st1.start();
  34. st2.start();
  35. st3.start();
  36. }
  37. }
楼上这个例子必须注意:使用同步代码块是为了解决线程安全问题,防止出现卖票错乱,在同步代码块中的锁对象,多个线程必须是使用同一个锁对象。没有线程安全,不建议使用同步机制,因为会降低操作效率。
同步机制的方式有两种:
    同步代码块:
        格式:
            synchronized(锁对象){
                需要被同步的代码...
            }
         注意:任何的对象都可以作为一个锁对象。  
        同步函数:
               格式:
                     修饰符   synchronized   返回类型  函数名(){
                                 
                     }
定义实例如下:
public static synchronized void getMoney(){ //关闭
        while(true){ 
            //synchronized (o) {
                if(count>0){
                    System.out.println(Thread.currentThread().getName()+"取走了一千块,账户的总额还剩余:"+ (count-1000));
                    count-=1000;
                }else{
                    System.out.println("账户的余额不足...");
                    break;
                }
            //}
        }  

同步函数需要注意的细节:
       1、如果是非静态函数锁对象是this对象,而且同步函数锁对象是不能更改的。
       2、如果是静态函数中锁对象是当前函数所属 类文件对象
大家都知道使用锁同步时,每个线程使用的锁必须是同一个,所以切记以上2点细节。

推荐使用同步代码块。因为锁可以任意,可以指定同步代码,很灵活。


自定义线程还有一种方法就是实现Runnable接口。重写run方法,
具体步骤如下:
        1、自定义类实现Runnable接口,实现接口中run方法。把自定义线程任务写在run方法中。
        2、创建Runnable实现类对象。
        3、创建线程Thread对象,把Runnable实现类对象作为参数传递给线程Thread。
        4、调用Thread中start方法开启线程。
同样是卖票,用实现Runnable接口又如何呢? 且看代码:
    
    
  1. public class Demo6 {
  2. public static void main(String[] args) {
  3. //创建实现类对象。
  4. TickThread t = new TickThread();
  5. //创建线程3个。把实现类对象传递到线程
  6. Thread thread1 = new Thread(t,"一号窗口");
  7. Thread thread2 = new Thread(t,"二号窗口");
  8. Thread thread3 = new Thread(t,"三号窗口");
  9. //调用start方法开启线程。
  10. thread1.start();
  11. thread2.start();
  12. thread3.start();
  13. }
  14. }
  15. class TickThread implements Runnable{
  16. //这里就不需要static修饰了,因为只创建一个此类实例对象。
  17. int ticks=50;
  18. public void run(){
  19. synchronized ("哈哈"){
  20. while(true){
  21. if(ticks>0){
  22. System.out.println(Thread.currentThread().getName()+"售出"+ticks+"张票");
  23. ticks--;
  24. }else{
  25. System.out.println("票已经售馨...");
  26. break;
  27. }
  28. }
  29. }
  30. }
  31. }
推荐使用:实现Runnable接口的方式。 因为java是单继承语言,如果自定义还需要有其他操作,继承了Thread很有局限。

注意: Runnable实现类的对象其实并不是一个线程对象,只是实现了Runnable接口类的对象而已。
         只有是Thread或者Thread的子类才是一个线程对象。
在调用Thread对象的start方法开启一个线程的时候,那么Thread对象就会去执行自己类中的run方法,其实这内部调用了Runnable的实现类的run方法,换菊花说实际上 是把Runnable实现类的run方法作为了Thread对象的任务代码去执行了。   


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

  



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值