Java Thread part 2

线程的四种状态

1. 新建(new) : 在一个线程新建时会短暂的处于这种状态,之后调度器可以将其转为就绪或阻塞

2. 就绪(runnable) : 这种状态下,线程在任意时间可以运行,也可以不运行

3. 阻塞(blocked) : 这种状态下,线程被阻止运行。只有当其重新进入就绪状态才能继续运行

4. 死亡(dead) : 线程不再可调度

进入阻塞状态的原因

1. sleep() 方法的调用

2. Object类的wait()方法的调用,直到收到notify()或notifyAll()的消息

3. 线程任务在等待输入

4. 在调用同步方法而对象锁不可用时

下面是一个阻塞线程的中断例子

package threadtest2;

import java.util.concurrent.TimeUnit;

public class SleepBlocked extends Thread {
    /**
     * 进入一秒的睡眠阻塞
     */
    @Override
    public void run() {
        try {
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            System.out.println("Sleep blocked has been interrupted");
        }
    }
}

package threadtest2;

import java.io.IOException;
import java.io.InputStream;

public class IOBlocked extends Thread {
    InputStream in;
    
    public IOBlocked(InputStream is) {
        this.in = is;
    }

    /**
     * 等待输入进入IO阻塞
     */
    @Override
    public void run() {
        System.out.println("Waiting for read");
        try {
            in.read();
        } catch (IOException e) {
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("IOBlock is interrupted");
            } else {
                throw new RuntimeException(e);
            }
        }
        System.out.println("Exiting IOBlocked.run()");
    }
}

package threadtest2;

public class SyncBlocked extends Thread {
    /**
     * 线程构造方法内即调用f()
     */
    public SyncBlocked() {
        (new Thread() {
            @Override
            public void run() {
                f();
            }
        }).start();
    }
    
    /**
     * 永不释放的锁方法
     */
    public synchronized void f() {
        while (true);
    }
    
    /**
     * 调用f()时进入阻塞
     */
    @Override
    public void run() {
        System.out.println("Trying to call f()");
        f();
        System.out.println("Exiting SyncBlocked.run()");
    }
}

package threadtest2;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class Interrupting {
    private static ExecutorService exec =
            Executors.newCachedThreadPool();
    private static void test(Runnable r) throws InterruptedException {
        Future<?> f = exec.submit(r);
        TimeUnit.MILLISECONDS.sleep(100);
        System.out.println("Interrupting " + r.getClass().getName());
        f.cancel(true);    // 通过Future的cancel()方法中断线程运行,和interrupt()效果一致
        System.out.println("Interrupt signal sent to " + r.getClass().getName());
    }
    
    /**
     * 最后的输出证明sleep阻塞可以被中断
     * 而IO和Sync的阻塞不可被中断
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        test(new SleepBlocked());
        test(new IOBlocked(System.in));
        test(new SyncBlocked());
        TimeUnit.SECONDS.sleep(3);
        System.out.println("Aborting with System.exit(0)");
        System.exit(0);
    }
}

1) 通过关闭使用资源来中止阻塞

package threadtest2;

import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class CloseResource {
    public static void main(String[] args) throws Exception {
        ExecutorService exec = Executors.newCachedThreadPool();
        ServerSocket ss = new ServerSocket(8080);
        InputStream socketInput = 
                new Socket("localhost", 8080).getInputStream();
        exec.execute(new IOBlocked(socketInput));
        exec.execute(new IOBlocked(System.in));
        TimeUnit.MILLISECONDS.sleep(100);
        System.out.println("Shutting down all threads");
        exec.shutdownNow();    // 至此所有线程是不能关闭的
        TimeUnit.SECONDS.sleep(1);
        System.out.println("Closing " + socketInput.getClass().getName());
        socketInput.close();    // 只有当正在使用的资源关闭后才能关闭线程
        TimeUnit.SECONDS.sleep(1);
        System.out.println("Closing " + System.in.getClass().getName());
        System.in.close();
    }
}

Waiting for read
Waiting for read
Shutting down all threads
Closing java.net.SocketInputStream
IOBlock is interrupted
Exiting IOBlocked.run()
Closing java.io.BufferedInputStream

IOBlock is interrupted
Exiting IOBlocked.run()

2) 通过使用NIO来响应阻塞的IO线程的中断请求

package threadtest2;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.SocketChannel;

public class NIOBlocked extends Thread {
    private final SocketChannel sc;
    public NIOBlocked(SocketChannel sc) { this.sc = sc; }
    @Override
    public void run() {
        System.out.println("Waiting for read in " + this);
        try {
            sc.read(ByteBuffer.allocate(1));
        } catch (ClosedByInterruptException e) {
            // 一个通过interrupt()或者cancel()来中断阻塞的异常
            System.out.println("ClosedByInterruptException accured");
        } catch (AsynchronousCloseException e) {
            // 一个通过关闭正在使用的资源中断阻塞的异常
            System.out.println("AsynchronousCloseException accured");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        System.out.println("Exiting NIOBlocked.run() " + this);
    }
}

package threadtest2;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class NIOInterrupting {
    public static void main(String[] args) throws Exception {
        ExecutorService exec = Executors.newCachedThreadPool();
        ServerSocket ss = new ServerSocket(8080);
        InetSocketAddress isa =
                new InetSocketAddress("localhost", 8080);
        SocketChannel sc1 = SocketChannel.open(isa);
        SocketChannel sc2 = SocketChannel.open(isa);
        Future<?> f = exec.submit(new NIOBlocked(sc1));
        exec.execute(new NIOBlocked(sc2));
        exec.shutdown();
        TimeUnit.SECONDS.sleep(1);
        f.cancel(true);    // 使用NIO可以直接cancel掉阻塞的thread
        TimeUnit.SECONDS.sleep(1);
        sc2.close();    // 也可以通过close正在使用的资源来
    }
}

Waiting for read in Thread[Thread-0,5,main]
Waiting for read in Thread[Thread-1,5,main]
ClosedByInterruptException accured
Exiting NIOBlocked.run() Thread[Thread-0,5,main]
AsynchronousCloseException accured
Exiting NIOBlocked.run() Thread[Thread-1,5,main]

一个可以被中断的锁

package threadtest2;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class LockBlocked extends Thread {
    ReentrantLock lock = new ReentrantLock();
    
    public LockBlocked() {
        lock.lock();
    }
    
    @Override
    public void run() {
        System.out.println("Waiting for lock");
        try {
            // 这是一个可以被interrupt打断的锁
            lock.lockInterruptibly();
        } catch (InterruptedException e) {
            System.out.println("Interrupted from LockBlocked.run()");
        }
        System.out.println("Broken out of constructor lock");
    }
    
    public static void main(String[] args) throws InterruptedException {
        Thread t = new LockBlocked();
        t.start();
        TimeUnit.SECONDS.sleep(2);
        t.interrupt();
    }
}

Waiting for lock
Interrupted from LockBlocked.run()
Broken out of constructor lock

原文地址:https://www.cnblogs.com/zemliu/p/2941403.html