1)实现Runnable接口
2)继承Thread类
3)线程池,默认采用 DefaultThreadFactory ,它会给线程池创建的线程设置一些默认值,最终是通过Thread类创建线程的
4)实现Callable接口,Callable 和与之相关的 Future、FutureTask,它们可以把线程执行的结果作为返回值返回
5)定时器Timer
。。。。。。
Runnable实现线程需要调用start()方法,它的本质也是调用run()方法
@Override public void run() { if (target != null) { target.run(); } }Thread实现线程会重写run方法,run方法里是要执行的任务,最终还是通过start方法调用run方法。
对于 Java 而言,最正确的停止线程的方式是使用 interrupt,但是interrupt只是起到通知的作用,停不停止由线程自己决定。java本质是想线程之间相互协作,如果贸然停止这样会造成一些不安全的操作。
while (!Thread.currentThread().islnterrupted() && more work to do) { do more work } 源码中可以看到,JDK使用while循环判断线程中断标记位是否被设置,只有以上两个条件都成立才会进行下一步。
其实是可以的,通过sleep、wait等方式让线程阻塞进入休眠状态是可以感受中断信号的,并且会抛出InterruptedException异常,同时清除中断信号。
1)stop ,stop会直接中断线程,不安全
2)suspend/resume ,这两种方式不会释放锁,就开始进入休眠模式,可能造成死锁问题。
这些方法已经被标记为@Deprecated。
3)volatile,出于线程休眠的线程是不会感知到被volatile标记的变量的
1)New(新建),当我们用 new Thread() 新建一个线程时,如果线程没有开始运行 start() 方法,那么它就是新建状态
2)Runnable(可以运行),调用start方法后进入Runnable状态,此时线程可能运行,也可能等待Cpu资源。
3)Blocked(被阻塞), 进入synchronized 保护的代码时没有抢到 monitor 锁,会被阻塞。
4)Waiting(等待),进入Waiting有三种可能性
没有设置 Timeout 参数的 Object.wait() 方法。
没有设置 Timeout 参数的 Thread.join() 方法。
LockSupport.park() 方法
Blocked 与 Waiting 的区别是 Blocked 在等待其他线程释放 monitor 锁,而 Waiting 则是在等待某个条件,比如 join 的线程执行完毕,或者是 notify()/notifyAll() 。
5)Timed Waiting(计时等待)与上面Waiting类似,在于有没有时间限制。以下有几种进入Timed Waiting的方式
设置了时间参数的 Thread.sleep(long millis) 方法;
设置了时间参数的 Object.wait(long timeout) 方法;
设置了时间参数的 Thread.join(long millis) 方法;
设置了时间参数的 LockSupport.parkNanos(long nanos) 方法和 LockSupport.parkUntil(long deadline) 方法。
6)Terminated(被终止),想要进入Terminated有两种可能。
run() 方法执行完毕,线程正常退出。
出现一个没有捕获的异常,终止了 run() 方法,最终导致意外终止。
如果想要确定线程当前的状态,可以通过 getState() 方法,并且线程在任何时刻只可能处于 1 种状态。
1)wait 必须在 synchronized 保护的同步代码中使用,没有synchronized 保护的代码不能保证原子性。而且wait会释放monitor锁,所以线程需要进入synchronized 获得锁。有时会出现虚假唤醒,所以我们需要while循环判断
while (condition does not hold) obj.wait();2)为什么 wait/notify/notifyAll 被定义在 Object 类中,而 sleep 定义在 Thread 类中?
因为 Java 中每个对象都有一把称之为 monitor 监视器的锁,由于每个对象都可以上锁,这就要求在对象头中有一个用来保存锁信息的位置。这个锁是对象级别的,而非线程级别的,wait/notify/notifyAll 也都是锁级别的操作,它们的锁属于对象,所以把它们定义在 Object 类中是最合适,因为 Object 类是所有对象的父类。因为如果把 wait/notify/notifyAll 方法定义在 Thread 类中,会带来很大的局限性,比如一个线程可能持有多把锁,以便实现相互配合的复杂逻辑,假设此时 wait 方法定义在 Thread 类中,如何实现让一个线程持有多把锁呢?又如何明确线程等待的是哪把锁呢?既然我们是让当前线程去等待某个对象的锁,自然应该通过操作对象来实现,而不是操作线程。3 ) wait/notify 和 sleep 方法的异同
1)BlockingQueue 实现生产者消费者模式
public static void main(String[] args) { BlockingQueue<Object> queue = new ArrayBlockingQueue<>(10); Runnable producer = () -> { while (true) { queue.put(new Object()); } }; new Thread(producer).start(); new Thread(producer).start(); Runnable consumer = () -> { while (true) { queue.take(); } }; new Thread(consumer).start(); new Thread(consumer).start(); } Condition 实现生产者消费者模式 public class MyBlockingQueueForCondition { private Queue queue; private int max = 16; private ReentrantLock lock = new ReentrantLock(); private Condition notEmpty = lock.newCondition(); private Condition notFull = lock.newCondition(); public MyBlockingQueueForCondition(int size) { this.max = size; queue = new LinkedList(); } public void put(Object o) throws InterruptedException { lock.lock(); try { while (queue.size() == max) { notFull.await(); } queue.add(o); notEmpty.signalAll(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (queue.size() == 0) { notEmpty.await(); } Object item = queue.remove(); notFull.signalAll(); return item; } finally { lock.unlock(); } } } wait/notify 实现生产者消费者模式 class MyBlockingQueue { private int maxSize; private LinkedList<Object> storage; public MyBlockingQueue(int size) { this.maxSize = size; storage = new LinkedList<>(); } public synchronized void put() throws InterruptedException { while (storage.size() == maxSize) { wait(); } storage.add(new Object()); notifyAll(); } public synchronized void take() throws InterruptedException { while (storage.size() == 0) { wait(); } System.out.println(storage.remove()); notifyAll(); } }