zoukankan      html  css  js  c++  java
  • Java多线程(一) 多线程的基本使用

      在总结JDBC数据库连接池的时候,发现Java多线程这块掌握得不是很好,因此回头看了下多线程的内容。做一下多线程模块的学习和总结,稳固一下多线程这块的基础。关于多线程的一些理论知识,这里不想啰嗦太多,可以进行下搜索了解。

    1. 如何使用Java创建多线程

      使用Java多线程,总的来说方法有两种:①继承Thread类,重写run方法  ②把相关的类实现Runnable(可运行)接口,重写run方法。③实现Callable接口(相对用得较少)

     1 package com.scl.thread;
     2 
     3 public class TestThread
     4 {
     5     public static void main(String[] args) throws Exception
     6     {
     7         String mainName = Thread.currentThread().getName();
     8         System.out.println(mainName + "线程开始运行");
     9 
    10         // 方法1 使用继承对线程进行调用
    11         MyThread myThread = new MyThread();
    12         myThread.setName("wft");
    13         myThread.start();
    14         myThread.join();
    15 
    16         // 方法2 继承Runnable接口进行调用
    17         Thread thread = new Thread(new MyRunnable());
    18         thread.start();
    19 
    20         System.out.println(mainName + "线程结束");
    21     }
    23 }
    24 
    25 // 使用runnable开启线程
    26 class MyRunnable implements Runnable
    27 {
    28     @Override
    29     public void run()
    30     {
    31         // 获取调用线程的名字
    32         String curName = Thread.currentThread().getName();
    33         System.out.println(curName + "线程启动");
    34         try
    35         {
    36             Thread.sleep(1000);
    37             System.out.println(curName + "正在运行");
    38         }
    39         catch (InterruptedException e)
    40         {
    41             e.printStackTrace();
    42         }
    43         System.out.println(curName + "线程结束");
    44     }
    45 }
    46 
    47 // 使用Thread进行run方法的编写,开启线程
    48 class MyThread extends Thread
    49 {
    50     // Thread.currentThread()调用这个方法的线程名称。
    51     String s = Thread.currentThread().getName(); // 调用这个类的是main方法调用,run方法交由新线程操作
    52 
    53     public MyThread()
    54     {
    55         System.out.println("Thread.currentThread().getname()=" + Thread.currentThread().getName());
    56         // 线程没运行前初始化的名字.因为类的初始化跟线程运行无关,这里返回的是处世话的名字
    57         System.out.println("This.getName=" + this.getName());
    58     }
    59 
    60     @Override
    61     public void run()
    62     {
    63         // run方法交由新线程操作,所以调用的名称不是main
    64         String strName = Thread.currentThread().getName();
    65         System.out.println("this.getName " + this.getName());
    66         // main
    67         System.out.println("do u no s?" + s);
    68 
    69         System.out.println(strName + " 开始数数");
    70         for (int i = 0; i < 100; i++)
    71         {
    72             System.out.println(strName + " " + i);
    73         }
    74         System.out.println(strName + " 数数完毕");
    75     }
    76 
    77     // 返回设置的name
    78     public String bName()
    79     {
    80         return this.getName();
    81     }
    82 }

          最应该注意的是给线程标注名称的时候,应该多使用Thread.currentThread().getname() 来获取线程名称。使用this.getName方法很容易出错。

         主要该注意的有如下两个:

         ① 获取名称不在run方法里面,永远返回名称为main。因为在构造线程类的时候,主线程main会进行代码的初始化。run方法由新创建起来的线程去调用,这样run方法里面的名称才能被正确获取到

         ② 在继承类的构造函数内,如上面MyThread的构造函数内调用getName()方法。该方法是由JDK 源码Thread类继承而来。new一个Thread实例时,系统会调用Thread

    下的方法,代码如下

       //Thread 类构造函数
        public Thread() {
            init(null, null, "Thread-" + nextThreadNum(), 0);
        }
    
    
       // 私有的init方法
        private void init(ThreadGroup g, Runnable target, String name,long stackSize) {
            init(g, target, name, stackSize, null);
        }
    
      //init 方法. 更详细内容见JDK源码Thread类363行
      private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc) 

          所以在构造器内的初始化的时候调用init方法给线程设置name字段。导致参数名称修改且以"Thread-"开头。初始化完毕后,如果用户设置过相关的线程名称,系统会把该字段进行修改,可以运用上述代码中的bName()函数进行验证。

      在使用Java多线程的时候,不要直接调用某个实例下的run方法,如果直接使用run方法。则直接调用,不会开辟新的线程进行功能操作。

           继承Thread和实现Runnable接口的区别:

      ① 继承Thread能够简单地实现线程开辟,但由于Java只支持单继承。继承Thread方法实现线程会有比较多的局限性

           ② 实现Runnable接口能够很好的将线程代码和业务逻辑代码分离,但代码结构相对复杂。一般都会使用实现Runnable方法创建线程。

    2. Java多线程下常用方法

      ① join( )  多线程是有cpu分配执行时间片段,如果要控制线程操作流程,则需要使用到join方法。join方法会阻塞主线程,主线程会等待join方法的线程执行完毕再继续执行后续的操作。同时join方法可以添加时间,让主线程等待一段时间,如果时间过了。则不再等待继续执行。如:thread.join( ),当主线程编译到该代码时,主线程会停止下来等待thread线程执行完毕后,主线程再继续后续操作

      ② sleep( )  不释放锁资源,让调用的线程进行等待。如:thread.sleep( ) ,但代码执行到这一句时,thread会停止下来等待,直到被唤醒或者等到到sleep到的时间点后再进行后续操作。

      ③ wait( )和notify( )、notifyAll( )  。这三个方法主要处理线程同步数据时使用。数据同步,也就是几条线程在同时修改一份共享数据。如火车站5名销售员同时在售卖火车票,火车票是固定数量的前提下,如何实现这5名销售员同时知道火车票库存、同一路段火车票售卖、车票信息共享等。

          wait方法使当前线程暂停执行并释放对象锁标志。notify和notifyall方法会唤醒几个等待的线程,让线程重新获取锁代码以便后续进行。线程状态图表如下:

           

          关于使用锁以及线程状态内容,将在下一篇博文进行总结,上述内容若有问题,烦请指出纠正。 

  • 相关阅读:
    Java_swing控件实例
    java_泛型 TreeSet 判断hashcode/length(升序排列)
    java_泛型(设置通配符下限)
    java_泛型(构造器)部分实例
    子类可以继承的同时实现接口
    继承类的线程写法
    匿名内部类的线程写法
    接口作为参数并用参数变量可以调用接口中的方法------------------需要多练习
    类可以作为参数类型,参数的变量还能调用作为参数类型的方法--------------需要多练习
    接口和类
  • 原文地址:https://www.cnblogs.com/doucheyard/p/5674351.html
Copyright © 2011-2022 走看看