关于java:Java-并发编程系列2-线程创建-优先级

  • 学习笔记 《 深刻了解 Java 虚拟机》
  • 学习笔记 《 后端架构设计》
  • 学习笔记 《 Java 基础知识进阶》
  • 学习笔记 《 Nginx 学习笔记》
  • 学习笔记 《 前端开发杂记》
  • 学习笔记 《 设计模式学习笔记》
  • 学习笔记 《 DevOps 最佳实际指南》
  • 学习笔记 《 Netty 入门与实战》
  • 学习笔记 《 高性能MYSQL》
  • 学习笔记 《 JavaEE 罕用框架》
  • 学习笔记 《 Java 并发编程学习笔记》
  • 学习笔记 《 分布式系统》
  • 学习笔记 《 数据结构与算法》

Java人造反对多线程,在 java.lang 包实现了一些对多线程反对的类,Thread 以及 Runnable接口,Thread继承了Runnable接口。

1、创立线程

能够通过继承Thread或者继承Runable来实现多线程,应用start() 办法来启动线程,比方上面的代码

// 继承Thread,重写run() 办法
public class MyThread extends Thread {

  @Override
  public void run() { } // 重写Run 办法
}

// 实现Runnable 接口
public class MyRunnable implements Runnable {

  @Override
  public void run() { }// 重写Run 办法
}

应用线程的代码示例

  Thread thread = new MyThread();
  thread.start();

  Thread runnableThread = new Thread(new MyRunnable(), "ThreadName");
  runnableThread.start();
  
  // 因为Runable是一种 FunctionalInterface,所以能够应用Lambda 表达式的形式实现
  // 但实质和runnableThread 并无区别
  Thread functionStyleThread = new Thread(() -> {}, "functionStyleThread");
  functionStyleThread.start();

手动调用run() 放和调用一个对象的一般办法没有什么实质上的区别.
启动一个线程,应用start()办法,start()办法是一个原生的native办法,其办法签名为 public synchronized void start();   如果线程曾经启动了,再次启动则会抛llegalThreadStateException  异样

2、线程优先级

上文中创立了两个线程,线程的执行是具备随机性的,由操作系统是否调配工夫片来决定是否执行。咱们能够通过设置操作线程的优先级来设置线程执行的优先级,优先级高的线程调配的工夫片更高,优先级低的线程调配的工夫片少。

计算密集型工作次要耗费大量CPU资源,不停进行计算。因为依附CPU性能,始终占用CPU进行计算,也就说个别状况下可能采纳多任务的数量等于CPU外围数。为了避免独占CPU,所以个别设置为低优先级。

 IO密集型工作(磁盘读取,web服务)次要须要IO的读取,利用CPU的效率较低,大量工夫破费在IO上。该种任高优先级比拟适宜。

在创立线程的时候,创立的线程会默认的继承父线程的一些属性,包含线程优先级,是否是守护线程,以及线程组等信息。线程的优先级并不是默认为5,而是继承父线程的优先级。其init()办法的局部代码如下:

private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc,
                  boolean inheritThreadLocals) {
    this.name = name;
    Thread parent = currentThread();
    this.group = g; // 设置线程组
    this.daemon = parent.isDaemon(); // 设置是否是守护线程,其值默认等于父线程的属性值
    this.priority = parent.getPriority(); 
    setPriority(priority); // 设置线程优先级,默认值等于父线程的优先级
    
    // 继承父线程的属性
    if (inheritThreadLocals && parent.inheritableThreadLocals != null)
        this.inheritableThreadLocals =
            ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);


    // 生成线程的ID,办法签名为 private static synchronized long nextThreadID()
    tid = nextThreadID();
}

3、线程优先级生效

在开发的过程中,咱们并不不能依赖线程的优先级,来实现业务,这是因为在不同的操作系统中,对线程的布局有所差别,有的甚至会疏忽线程的优先级,比方 MacOS 或者 Ubuntu。
上面的代码中,创立了两个线程,一个设置高优先级一个设置低优先级,察看最初的输入后果会发现,两个执行并没有太大的差异,所以线程的优先级在某些操作系统或者某些JVM实现上可能有所差别。

private static volatile boolean start = false;

private static volatile boolean end = false;

public static void main(String[] args) throws InterruptedException {
  PriorityThread runnable1 = new PriorityThread();
  PriorityThread runnable2 = new PriorityThread();

  // 设置线程优先级 
  // MIN_PRIORITY = 0; NORM_PRIORITY=5;  MAX_PRIORITY = 10
  runnable1.setPriority(Thread.MIN_PRIORITY);
  runnable2.setPriority(Thread.MAX_PRIORITY);

  runnable1.start();
  runnable2.start();

  start = true;
  TimeUnit.SECONDS.sleep(2);
  end = true;

  // 输入执行的后果
  System.out.println("count1 = " + runnable1.count);
  System.out.println("count2 = " + runnable2.count);
}

static class PriorityThread extends Thread {

  private Long count = 0L;

  @Override
  public void run() {
    // 没有开始,则始终让出线程执行的工夫片
    while (!start) {
      Thread.yield();
    }

    // 开始执行,每次执行都让出工夫片
    while (!end) {
      Thread.yield();
      count++;
    }
  }
}

依据下面的代码,咱们预估,线程2因为优先级高,所以其count值应该会比线程1高,然而后果却是两者差异并不大。这因为笔者的操作系统MacOS,操作系统疏忽了线程的优先级,所以在线程让出工夫片的时候并不会无限调配给高优先级的线程来执行。读者可自定在不同的操作系统尝试下面的代码,察看不同的操作系统是否对线程优先级进行疏忽。

count1 = 5531926
count2 = 5525194

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理