玩转多线程

Posted joeye153

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了玩转多线程相关的知识,希望对你有一定的参考价值。

玩转多线程

目录:

  • 创建多线程的三种方式
    • extends Thread
    • implements Runnable
    • 匿名类
      • 线程创建方式
      • 有关构造函数中使用匿名类的说明
  • 多线程的核心理论
    • 共享性
    • 互斥性
    • 原子性
    • 可见性
    • 有序性
  • synchronized
    • 使用方法
    • 内核剖析
  • volatile
    • 使用方法
    • 使用场景
  • 多线程生命周期图
  • 线程安全的容器

多线程的内容有的是笔者自己总结,有的会直接推荐优质博客。

自己总结的部分一般包含个人实践时的经验和需要注意的坑点。

创建多线程的三种方式

三种方式的核心均是对Thread类中run方法进行override

1.extends Thread
public class CreateThreadMethod {
    public static void main(String[] args) {
        extendsMethod thread = new extendsMethod();
        thread.start();
    }
}

class extendsMethod extends Thread {
    @Override
    public void run() {
        for (int i = 9; i >= 0; i--) {
            System.out.println("extendsMethod's Thread:" + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
            }
        }
    }
}
2.implements Runnable
public class CreateThreadMethod {
    public static void main(String[] args) {
        Thread thread = new Thread(new implementsMethod());
        thread.start();
    }
}

class implementsMethod implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("implementsMethod's Thread:" + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
            }
        }
    }
}
3.匿名类

多线程创建方式:

public class CreateThreadMethod {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 9; i >= 0; i--) {
                    System.out.println("The third method's Thread:" + 3 * i);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                    }
                }
            }
        });
        thread.start();

    }
}

有关匿名类在构造函数中使用的说明:

先看如下例子:

public class ThisEscape {
  private final int num;
 
  public ThisEscape(EventSource source) {
    //在构造函数中直接使用匿名类 
    source.registerListener(
        new EventListener() {
          public void onEvent(Event e) {
            doSomething(e);
          }
        });
    num = 42;
  }

  private void doSomething(Event e) {
    if (num != 42) {
      System.out.println("Race condition detected at " +
          new Date());
    }
  }
}

上述class编译之后分为两部分:

outer class:

public class ThisEscape {
  private final int num;

  public ThisEscape(EventSource source) {
    source.registerListener(new ThisEscape$1(this));
    num = 42;
  }

  private void doSomething(Event e) {
    if (num != 42)
      System.out.println(
          "Race condition detected at " + new Date());
  }

  static void access$000(ThisEscape _this, Event event) {
    _this.doSomething(event);
  }
}

anonymous inner class:

class ThisEscape$1 implements EventListener {
  final ThisEscape this$0;

  ThisEscape$1(ThisEscape thisescape) {
    this$0 = thisescape;
    super();
  }

  public void onEvent(Event e) {
    ThisEscape.access$000(this$0, e);
  }
}

试想:如果一个线程足够快,那么就有可能在num还被初始化为42之前,匿名类已经调用了doSomething()这个时候就会抛出NullPointerException

那么一个类的构造函数要怎么写才会避免类似的错误出现呢?

  • 永远不要在构造器内创建内部类,无论是匿名类,还是staticnon-static
  • 在构造器中不要把this当成参数传递给其他的类或方法
  • 在构造器中只调用private方法

多线程的核心理论

详见博客:多线程的核心理论

synchronized:

对方法加锁 == 对对象加锁,即synchronized this

关于synchronized的内核剖析详见博客:synchronized的内核剖析

volatile

个人使用经验是:对于一些标志位,常采用volatile

关于volatile的具体解析:volatile

多线程生命周期图

技术图片

思考:图中涉及的wait方法和sleep方法,为什么wait方法在Object类,而sleep方法在Thread类?

两者都可以让线程暂停一段时间,但是本质的区别在于sleep方法是线程的运行状态控制,而wait方法是线程之间的通讯

线程安全的容器:

详见博客:线程安全的容器

以上是关于玩转多线程的主要内容,如果未能解决你的问题,请参考以下文章

带你玩转多进程编程

带你玩转多进程编程

分布式软总线让阿里巴巴商家玩转多设备直播

转多线程设计模式 - Future模式之JAVA原生实现

Windows下PP-Tracking多目标跟踪数据训练

玩转Bash变量