1、什么是线程
线程是CPU进行调度的最小单位
多线程的特点:异步和并行
2、并发和并行的区别
并发:单个CPU在一定的时间间隔内靠时间片切换处理多个任务,他不可能真正的同时执行多个任务。
并行:多个CPU在同一时刻同时处理多个任务,是真正的同时处理
3、java中创建线程的方式
(1)继承Thread类
public class ThreadDemo extends Thread {
/**
* If this thread was constructed using a separate
* {@code Runnable} run object, then that
* {@code Runnable} object's {@code run} method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of {@code Thread} should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
System.out.println("子线程处理任务...");
}
public static void main(String[] args) {
Thread thread = new Thread(new ThreadDemo());
thread.start();
System.out.println("main线程处理任务...");
}
}
(2) 实现Runable接口
public class RunableDemo implements Runnable{
/**
* When an object implementing interface {@code Runnable} is used
* to create a thread, starting the thread causes the object's
* {@code run} method to be called in that separately executing
* thread.
* <p>
* The general contract of the method {@code run} is that it may
* take any action whatsoever.
*
* @see Thread#run()
*/
@Override
public void run() {
System.out.println("子线程处理任务...");
}
public static void main(String[] args) {
Thread thread = new Thread(new RunableDemo());
thread.start();
System.out.println("main线程处理任务...");
}
}
(3)实现Callable接口
如果想要获取线程的执行结果,可以用这个。使用线程池提交一个任务,用Future的get方法获取结果,线程池使用完记得关闭。
public class CallableDemo implements Callable<String> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
@Override
public String call() throws Exception {
return "任务执行成功";
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<String> submit = executorService.submit(new CallableDemo());
try {
System.out.println("线程执行结果:" + submit.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
}
}
(4)线程池创建线程
一个核心线程的线程池,最大线程数也是1
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
固定大小的线程池,核心线程数和最大线程数相等,都是传入的参数
ExecutorService executorService2 = Executors.newFixedThreadPool(1);
具有缓存功能的线程池
ExecutorService executorService3 = Executors.newCachedThreadPool();
具有定时任务功能的线程池
ExecutorService executorService4 = Executors.newScheduledThreadPool(1);
4、线程的状态
java中线程的状态:6种
操作系统层面:5种
写一个案例来验证一下
public static void main(String[] args) {
new Thread(() -> {
while (true) {
try {
TimeUnit.SECONDS.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "thread-01").start();
new Thread(() -> {
while (true) {
synchronized (Test.class) {
try {
Test.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "thread-02").start();
new Thread(new TestDemo(), "TestDemo-01").start();
new Thread(new TestDemo(), "TestDemo-02").start();
}
static class TestDemo extends Thread {
@Override
public void run() {
while (true) {
synchronized (TestDemo.class) {
try {
TimeUnit.SECONDS.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
运行main方法,发生锁等待,使用jps命令找到我们启动的java进程的进程号,我这里是9712
然后再使用jstack打印堆栈信息, jstack 9712
`"thread-01" #15 prio=5 os_prio=0 cpu=0.00ms elapsed=26.77s tid=0x000002ebaa74d800 nid=0x5e60 waiting on condition [0x000000fc93eff000
]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(java.base@14.0.2/Native Method)
at java.lang.Thread.sleep(java.base@14.0.2/Thread.java:337)
at java.util.concurrent.TimeUnit.sleep(java.base@14.0.2/TimeUnit.java:446)
at com.alibaba.Test.lambda0(Test.java:37)
at com.alibaba.Test$$Lambda$15/0x0000000800b94440.run(Unknown Source)
at java.lang.Thread.run(java.base@14.0.2/Thread.java:832)
"thread-02" #16 prio=5 os_prio=0 cpu=0.00ms elapsed=26.77s tid=0x000002ebaa74e800 nid=0x5124 in Object.wait() [0x000000fc93ffe000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(java.base@14.0.2/Native Method) - waiting on <0x0000000711aa7170> (a java.lang.Class for com.alibaba.Test) at java.lang.Object.wait(java.base@14.0.2/Object.java:321) at com.alibaba.Test.lambda1(Test.java:48) - locked <0x0000000711aa7170> (a java.lang.Class for com.alibaba.Test) at com.alibaba.Test$$Lambda$16/0x0000000800b95040.run(Unknown Source) at java.lang.Thread.run(java.base@14.0.2/Thread.java:832)
"TestDemo-01" #18 prio=5 os_prio=0 cpu=0.00ms elapsed=26.77s tid=0x000002ebaa74f800 nid=0x1268 waiting on condition [0x000000fc940fe0 00] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(java.base@14.0.2/Native Method) at java.lang.Thread.sleep(java.base@14.0.2/Thread.java:337) at java.util.concurrent.TimeUnit.sleep(java.base@14.0.2/TimeUnit.java:446) at com.alibaba.TestTestDemo) at java.lang.Thread.run(java.base@14.0.2/Thread.java:832)
"TestDemo-02" #20 prio=5 os_prio=0 cpu=0.00ms elapsed=26.77s tid=0x000002ebaa751000 nid=0x7118 waiting for monitor entry [0x000000fc9
41ff000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.alibaba.TestTestDemo)
at java.lang.Thread.run(java.base@14.0.2/Thread.java:832)
`
可以看到thread-01:TIMED_WAITING,thread-02:WAITING,TestDemo-01:TIMED_WAITING,TestDemo-02:BlCOKED
这几个状态我们在Thread类的内部枚举类中都可以看到
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
* {@link Object#wait() Object.wait}.
*/
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 {@code Object.wait()}
* on an object is waiting for another thread to call
* {@code Object.notify()} or {@code Object.notifyAll()} on
* that object. A thread that has called {@code Thread.join()}
* 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;
}
5、线程的启动和停止
在java中是没有线程的概念的,我们调用start方法启动一个线程,实际上是调了一个本地方法启动了一个操作系统的线程
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
点进start方法的实现可以看到在start方法里面调了一个start0方法,而start0是一个本地方法 \
针对于不同的操作系统,jvm有不同的实现去启动一个线程。
在jvm的启动线程的方法中,又会回调我们java中的run方法,这里是使用了JNI的机制,这里不是重点,Hotspot源码就不看了
如何中断一个正在运行的线程
在java中提供了一个interrupt去友好地中断线程,不推荐使用stop方法强制中断,如果此时指令执行到一半,将会产生意想不到的异常。 \
public class InterruptDemo extends Thread {
/**
* If this thread was constructed using a separate
* {@code Runnable} run object, then that
* {@code Runnable} object's {@code run} method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of {@code Thread} should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("我在执行任务...");
}
}
public static void main(String[] args) {
Thread thread = new Thread(new InterruptDemo());
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
在未响应中断之前,一直在执行任务,循环调用isInterrupt方法判断是否中断,调用interrupt方法之后响应中断。
如何中断一个睡眠的线程?
线程在睡眠中也是可以响应中断的,调用Thread.sleep方法会强制你捕获异常InterruptedException来响应中断
public class InterruptDemo extends Thread {
/**
* If this thread was constructed using a separate
* {@code Runnable} run object, then that
* {@code Runnable} object's {@code run} method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of {@code Thread} should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread thread = new Thread(new InterruptDemo());
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
从运行结果中可以看到处于睡眠状态的线程响应了中断,但是只是响应,并没有真正的中断,可以看到进程还在。
在捕获到异常之后,我们再次中断,此时就会看到进程已经结束
这里其实就是在jvm中维护了一个状态变量interrupt,默认是false,当我们调用interrupt方法之后设置成true。