会有些朋友不是很能理解上期关于内存的知识,这里再给大家讲讲Java中的一些线程知识,希望可以给大家带来一些启发。
线程创建、运行
Java中的三种线程创建方式
一起吹水聊天
Thread
public class ThreadTest {
public static class MyThread extends Thread {
@Override
public void run() {
// this获取当前线程,相当于Thread.currentThread()
System.out.println(this + " here");
}
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
}
下面是Thread类
public class Thread implements Runnable {
// 大量的类和方法...
}
Runnable
public class ThreadTest {
public static class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread() + " here");
}
}
public static void main(String[] args) {
MyRunnable task = new MyRunnable();
new Thread(task).start();
new Thread(task).start(); // 可以启动多个
}
}
Runnable接口
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Callable FutureTask
public class ThreadTest {
public static class CallerTask implements Callable<String> {
@Override
public String call() throws Exception {
return "hello";
}
}
public static void main(String[] args) {
FutureTask<String> futureTask = new FutureTask<>(new CallerTask());
new Thread(futureTask).start();
try {
String result = futureTask.get(); // 返回结果
System.out.println(Thread.currentThread() + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
* @return computed result
*/
V call() throws Exception;
}
public class FutureTask<V> implements RunnableFuture<V> {
// 类和方法...
}
线程中的方法
join
如果想让某几件事情做完之后再进行下面的事情,就可以用join()
方法。是Thread
中的方法。
一起吹水聊天
threadA.join(); // 当main线程执行到这里,会阻塞,等到ThreadA执行完毕后再执行ThreadB()
threadB.join(); // 同理,会再次阻塞。
sleep
线程被阻塞,持有的锁或监视器资源不会释放,睡眠时间到了之后就会回到就绪状态,获取CPU后继续执行。
Thread.sleep(1000);
yield
当一个线程使用yield
方法时,暗示线程调度器当前线程要让出CPU资源,但是线程调度器可以忽略这个暗示。如果执行成功,线程会进入就绪状态。
线程状态
Java中线程分为六种状态
- New(新建)
- Runnable(可运行)
- Blocked(阻塞)
- Waiting(等待)
- Timed waiting(计时等待)
- Terminated(终止)
- Java没有将正在运行作为一个单独的状态。一个正在运行的线程仍然处于可运行的状态。
- 线程调度的细节依赖于操作系统提供的服务。
New(新建)
当用new操作符创建一个新线程时,如
new Thread()
;
Runnable(可运行)
一旦调用
start()
方法,线程就处于可运行状态
阻塞、等待、计时等待
当线程处于阻塞或等待状态时,它暂时是不活动的。它不运行任何代码,而且消耗最少的资源。要由线程调度器重新激活这个线程。具体细节取决于它是怎样达到非活动状态的。
- 当一个线程试图获取一个内部的对象锁,而且这个锁目前被其它线程占用,就会进入阻塞状态。
- 当线程等待另一个线程通知调度器出现一个条件时,这个线程会进入等待状态。
- 有几个方法有超时参数,调用这些方法会让线程进入计时等待状态。知道超时期满或接收到适当的通知。
Terminated(终止)
线程会由于以下两个原因而终止
run()
方法正常退出,线程自然终止。- 因为一个没有捕获的异常终止了 run() 方法,使线程意外终止。
线程中的 6 个状态
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
就绪状态
所有条件都满足,只等待CPU来运行。或者因为当前时间片用完了,回到就绪状态。当阻塞结束后就是就绪状态。
线程属性
中断线程
线程终止:当线程的 run 方法执行方法体中最后一条语句后再执行 return 方法返回时,或者出现了方法中没有捕获的异常。
- 除了已经废弃的 stop 方法,没有办法可以强制终止线程。
interrupt()
方法可以用来请求终止一个线程。当调用interrupt
方法时,就会设置线程的中断状态。每个线程都应当不时地检查这个状态。如果线程被阻塞就无法检查中断状态,这里就要抛出InterruptedException
异常。- 用
Thread.currentThread().isInterrupted()
方法检查是否设置了中断状态。如果线程被阻塞再这么调用就会抛InterruptedException
异常。 interrupted()
方法检查是否设置了中断状态。与isInterrupted()
不同的是,如果发现当前线程被中断,则会清除中断标志。- 有些阻塞不能被中断:如
IO
阻塞。
没有任何语言要求被中断地线程应当终止。中断一个线程只要引起它地注意。被中断地线程可以决定如何相应中断。
守护线程
调用 t.setDaemon(true)
将一个线程转换为守护线程。该方法必需在线程启动之前调用。
守护线程只用来为其他线程提供服务。
当只剩下守护线程时,虚拟机就会退出。
即使main线程退出了,如果还有用户线程JVM进程就不会退出。
线程名
可以用 t.setName("")
为线程设置名称。