Java多线程系列1(线程基本常识)

1 线程的生命周期

线程的生命周期,经典图示意如下:

这里写图片描述

2 线程的生命周期解释如下:

1)New状态:
当调用 new Thread()时候,线程处于新建状态。此时JVM为线程分配内存空间,执行必要的初始化;
2)Runnable状态:
调用start(),此时线程会进入到线程等待队列,等待CPU的调度。此时线程处于Runnable状态;
3)Running状态:
线程抢占到CPU的执行权,此时CPU开始执行线程,此时处于Running状态;
4)Blocked状态:
Running状态的时候,会因为下面原因进入Blocked状态:
(1)执行synchronized等同步方法或者同步块,如果没有获取到同步锁,就会进入Blocked状态;如果获取到同步锁,继续保持Running状态执行;
(2)执行wait方法(此时隐含的条件是在同步块中可以获取到同步锁,因为wait执行的前提条件是必须在同步块中执行);
(3)执行sleep/join方法或者执行IO操作
其中,Blocked状态触发相应的条件又会跳转到其他状态:
(1)因为同步监视器导致的阻塞,后续获取到同步锁以后,不能立即进入Running状态,此时会进入Runnable状态,等待CPU执行权。一旦后续获得CPU执行权,又会变为Running状态;
(2)因为wait导致的阻塞,当收到同步对象的notify/notifyAll时,或者线程的interrupt()方法被调用,此时忧郁wait是在同步块中调用的,此时会还是会处于Blocked状态,需要获取同步锁才可以进入Runnable状态。所以这里隐含的意思就是:调用notify/notifyAll之后,一定要释放同步锁才可以让整个流程正常运转起来。比如:如果调用 notify/notifyAll之后,延时5秒才释放同步锁,此时可以看到大约5秒以后另一个线程才能获取到同步锁,继续从等待的地方开始执行
(3)因为sleep导致的阻塞,如果sleep时间到,会转为Runnable状态,竞争CPU执行权;
因为join导致的阻塞,在另外一个线程执行完毕以后,本线程转为Runnable状态,竞争CPU执行权;
因为阻塞式IO操作导致的阻塞,IO执行完毕以后,转为Runnable状态;
6) Dead状态
Runnable状态的线程,由于线程执行完毕或者或者抛出异常退出,会进入Dead状态。之后系统会回收线程使用的资源。

3 线程的创建方法

方法1: 继承Thread创建线程:

public class WorkThread extends Thread {
  public WorkThread() {} 
  @Override
  public void run() {
      //TODO: work
  }
}

方法2: 通过实现Runnable接口创建线程:

public class WorkRunnable implements Runnable {
   private String jobName;
   public WorkRunnable(String jobName) {
      this.jobName = jobName;
   }

   @Override
   public void run() {
       System.out.println("JobName is " + jobName);
   }
}
WorkRunnable runnable = new WorkRunnable ("job1");
Thread workThread = new Thread(runnable);
workThread.start();

4 线程的中断

与线程中断有关的方法为:

public class Thread {
    // 发出一个中断请求,把标志位设定为中断状态
    public void interrupt() { ... }

    // 用于检测标志位是否为中断的状态
    public boolean isInterrupted() { ... }

    // 调用以后返回是否为中断状态,同时清除当前线程的标志位的中断状态
    public static boolean interrupted() { ... }

    ...
}

interrupt()方法调用以后:
(1)如果正在执行正常的代码(非阻塞代码),会直接将中断标志置为中断状态,然后继续执行线程代码,线程可以使用interrupted()/isInterrupted()方法来检查线程是否中断,然后决定是否需要响应中断。
(2)如果处于阻塞状态(比如sleep/wait以及同步块导致的阻塞中),此时会抛出InterruptedException异常
(3)对于IO阻塞:interrupt()不会对IO阻塞有任何影响。IO操作完毕以后,才会继续向下执行。(也极IO阻塞是无法中断的)

5 不可中断的阻塞情况

以下几种情况,通过调用interrupt()方法是无法中断阻塞的:
(1)同步Socket I/O (需要调用socket.close()才可以终止)
(2)同步I/O(比如读写文件的read/write,需要调用close才可以终止)
(3)Selector的同步I/O
(4)获取某个锁
对于这4种情况,直接调用线程的interrupt()方法,不会终止socket操作/文件读写操作。要特别处理才可以中断退出。
后退,举个栗子:
以下是一个中断文件读写的例子:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;

/**
 * Created by Administrator on 2016/1/17 0017.
 */
public class test  {

    public static class  ReadFileThread extends Thread {
        InputStreamReader in = null;

        @Override
        public void run() {
            super.run();
            System.out.println("Time: " + System.currentTimeMillis() + "-- run");
            File file = new File("D:/bigDataFile.pdf");
            try {
                if (file.isFile() && file.exists()) {
                    in = new InputStreamReader(new FileInputStream(file));
                    BufferedReader buffer = new BufferedReader(in);
                    String lineText = null;
                    while ((lineText = buffer.readLine()) != null) {
                    }
                    System.out.println("Time: " + System.currentTimeMillis() + " -- Read over the file");
                }
            } catch (Exception e) {
               System.out.println("Time: " + System.currentTimeMillis() + " -- " + e.getMessage());
            } finally {
                try {
                    in.close();
                } catch (Exception e) {
                }
            }
            System.out.println("Time:" + System.currentTimeMillis() + " -- exit thread");
        }

        public void cancelRead() {
            try {
                in.close();
            } catch (Exception e) {

            }
        }
    }

    public static void main(String[] args) {
        ReadFileThread thread = new ReadFileThread();
        thread.start();
        try {
            Thread.currentThread().sleep(100);
        } catch (Exception e) {

        }
        thread.interrupt();
    }
}

测试结果如下:

Time: 1501298978228-- run
Time: 1501298979161 -- Read over the file
Time:1501298979161 -- exit thread

从执行结果看,调用interrupt()方法,根本无法中断文件读操作。读文件操作自然完成以后,线程才结束

修改以以上代码,不调用interrupt()方法,改为调用cancelRead来调用close()方法终止读操作:

    public static void main(String[] args) {
        ReadFileThread thread = new ReadFileThread();
        thread.start();
        try {
            Thread.currentThread().sleep(100);
        } catch (Exception e) {

        }
        thread.cancelRead();
    }

执行结果:

Time: 1501299346472-- run
Time: 1501299346571 -- Stream closed
Time:1501299346571 -- exit thread

可以看到读操作立即被终止,然后退出线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值