• 学习笔记《Java多线程编程实战指南》一


    1.1什么是多线程编程

      多线程编程就是以线程为基本抽象单位的一种编程范式,和面向对象编程是可以相容的,事实上Java平台中的一个线程就是一个对象。多线程编程不是线程越多越好,就像“和尚挑水”的故事一样。

    1.2为什么使用多线程

      提高程序运行效率。

    1.3线程的创建、启动和运行

      java.lang.Thread就是java平台对线程的实现。Thread类的两个常用构造器是:Thread()和Thread(Runnable target)。1.使用第一种构造器。创建Thread类的实现子类,即继承Thread类的类。2.使用第二种构造器。创建Runnable接口的实例,即实现Runnable接口的类。

      1.3.1 继承Thread类

     1 public class demo{
     2     public static void main(String[] args) {
     3         Thread  thread = new myDemo(); // 创建
     4         thread.start();  //启动
     5         System.err.println("thread1"+Thread.currentThread().getName());
     6 
     7     }
     8      
     9     class myDemo extends Thread{
    10         
    11         @Override
    12         public void run() { // 运行
    13             System.err.println("thread2"+Thread.currentThread().getName());
    14         }
    15     }
    16 }   

      1.3.2实现Runnable接口

     1 public class demo{
     2 
     3     public static void main(String[] args) {
     4         Thread  thread = new Thread(new myDemo()); // 创建
     5         thread.start(); // 启动
     6         System.err.println("thread1"+Thread.currentThread().getName());
     7 
     8     }
     9      
    10     class myDemo implements Runnable{
    11         
    12         @Override
    13         public void run() { // 运行
    14             System.err.println("thread2"+Thread.currentThread().getName());
    15         }
    16     }
    17 
    18 }

      1.3.3 注意

        1.线程属于“一次性用品”,不能多次调用同一线程的start方法,否则抛出 java.lang.IllegalThreadStateException异常

     1 public class demo{
     2 
     3     public static void main(String[] args) {
     4         Thread  thread = new Thread(new myDemo()); // 创建
     5         thread.start(); // 启动
               thread.start(); // 启动
               thread.start(); // 启动
     6         System.err.println("thread1"+Thread.currentThread().getName());
     7 
     8     }
     9      
    10     class myDemo implements Runnable{
    11         
    12         @Override
    13         public void run() { // 运行
    14             System.err.println("thread2"+Thread.currentThread().getName());
    15         }
    16     }
    17 
    18 }    

        2.不建议直接调用run方法,线程的run方法是由Java虚拟机直接调用的,如果在main方法中直接调用,运行是可以的,但是违背创建线程的初衷,线程的运行仍是mian线程。

    1.4线程创建的区别

      1.4.1 创建一个线程与创建其他类型的Java对象的不同。

        创建线程对象比创建其他类型的对象成本要高。这是因为Java虚拟机会为每个线程分配调用栈(Call Stack)所需的内存空间,调用栈用于跟踪Java代码方法间的调用关系。第二是因为每个线程可能有一个内核线程与之对应,与java虚拟机的实现有关。

       1.4.2 线程两种创建方式的区别 

        1.一种是基于继承的技术,创建Thread类的子类。另一种是基于组合的技术,以Runnable接口实例为构造器参数,创建Thread实例。基于组合相对于继承来说,类与类之间的耦合性更低,因此更灵活。

        2.从对象共享的角度来看,Runnable实例当作为多个线程的共享实例时,会出现竞态和线程安全问题

     1 public class demo {
     2     
     3     public static void main(String[] args) {
     4         Thread  t;    
     5         CountingTask ct = new CountingTask(); //创建Runnable实例
     6         // 获取处理器个数
     7         final int numberofProceesors = Runtime.getRuntime().availableProcessors();
     8         System.err.println("获取处理器个数"+numberofProceesors);
     9         for(int i=0; i<2*numberofProceesors; i++){    
    10             //直接创建线程
    11             t = new Thread(ct); //实例被共享
    12             t.start();
    13         }
    14         
    15         for(int i=0;i<2*numberofProceesors; i++){
    16             //以子类方式创建线程
    17             t = new CountingThread();
    18             t.start();
    19         }
    20     }
    21         
    22   static class Counter{
    23       private int count = 0;
    24       public void increment(){
    25           count++;
    26       }
    27       public int value(){
    28           return count;
    29       }
    30   }
    31     
    32   static class CountingTask implements Runnable{
    33         
    34       private Counter counter = new Counter();   
    35         @Override
    36         public void run() {
    37             for(int i=0;i<10;i++){
    38                 doSomething();
    39                 counter.increment();
    40             }
    41             System.err.println("Runnable"+counter.value());
    42         }
    43         
    44     }
    45   static class CountingThread extends Thread{
    46       private Counter counter = new Counter();
    47       @Override
    48       public void run() {
    49           for(int i=0;i<10;i++){
    50                 doSomething();
    51                 counter.increment();
    52             }
    53             System.err.println("Thread"+counter.value());
    54       }
    55   }
    56   static void doSomething(){
    57         try {
    58             Thread.currentThread().sleep(1000);
    59         } catch (InterruptedException e) {
    60             // TODO Auto-generated catch block
    61             e.printStackTrace();
    62         }
    63     }
    64 }  

    观察结果:

     1 获取处理器个数4
     2 Runnable64
     3 Runnable67
     4 Runnable69
     5 Runnable68
     6 Runnable67
     7 Runnable65
     8 Runnable64
     9 Runnable64
    10 Thread10
    11 Thread10
    12 Thread10
    13 Thread10
    14 Thread10
    15 Thread10
    16 Thread10
    17 Thread10

        3.从对象创建成本来看,创建一个线程实例要比创建一个普通的Runnable实例更昂贵。我的理解是new Thread( new Runnable()) = new Thread(),意思是一个线程实例(继承Thread)new Thread()的成本,等于实现Runnable接口方式下创建一个线程new Thread(参数)加 一个Runnable实例 ,类似于1+1=2,1<2的问题。

  • 相关阅读:
    HBase 文件读写过程描述
    Kafka 部署指南-好久没有更新博客了
    《Python高性能编程》——列表、元组、集合、字典特性及创建过程
    Ansible常用功能
    vim内替换文件内容
    线程队列-queue
    Python多进程
    python多线程知识-实用实例
    夜间模式的实现
    本地通知的实现
  • 原文地址:https://www.cnblogs.com/kkw105/p/10142984.html
Copyright © 2020-2023  润新知