写在前面: 多线程大家应该也不会陌生,同时也是面试的超级重点,掌握了多线程编程有利解决许多项目的并发性问题,提高自身硬实力。
并发编程的本质是充分利用cpu资源。
硬件:CPU、磁盘、网络、内存
软件: 线程数量、JVM内存分配、网络通信机制(BIO、NIO、AIO)、磁盘IO
并行:同一时刻,多个线程同时执行。(多个CPU同时执行多个线程)
并发:同一时刻,多个线程交替执行。(一个CPU交替执行线程)
用户注册案例,异步线程调度:
@RestController
public class UserController {
@Autowired
IUserService userService;
@Autowired
SmsClient smsClient;
@PostMapping("/user")
public String addUser(User user) {
long start = System.currentTimeMillis();
userService.insert(user);
long end = System.currentTimeMillis();
return "SUCCESS:" + (end - start);
}
//创建一个线程池对象
/**
* 参数信息:
* int corePoolSize 核心线程大小
* int maximumPoolSize 线程池最大容量大小
* long keepAliveTime 线程空闲时,线程存活的时间
* TimeUnit unit 时间单位
* BlockingQueue workQueue 任务队列。一个阻塞队列
*/
@PostMapping("/sms/user")
public String register(User user) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(4, 4, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(10));
long start = System.currentTimeMillis();
userService.insert(user);
//异步. Future ->
//会创建N个线程
//MQ来代替
pool.submit(new Runnable() {
@Override
public void run() {
smsClient.sendSms("xxxxx");
}
});
long end = System.currentTimeMillis();
pool.shutdown();
return "SUCCESS:" + (end - start);
}
}
Java线程的状态有6钟
public enum State {
// 创建
NEW,
// 运行时
RUNNABLE,
// 阻塞
BLOCKED,
// 等待,死死等待
WAITING,
// 超时等待
TIMED_WAITING,
// 销毁
TERMINATED;
}
需要注意的是,操作系统中的线程除去new
和terminated
状态,一个线程真实存在的状态,只有:
ready
:表示线程已经被创建,正在等待系统调度分配CPU使用权。running
:表示线程获得了CPU使用权,正在进行运算waiting
:表示线程等待(或者说挂起),让出CPU资源给其他线程使用Java创建Thread类调用start方法,底层是把线程放到一个组里面,然后调用一个本地方法start0;方法底层是C++;Java无法操作硬件。
new Thread().start(); // 启动一个线程
Thread t1 = new Thread();
t1.run(); // 调用实例方法
如下代码:
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 */
}
}
}
// 调度本地方法
private native void start0();
Java调用本地方法start0
后由JVM(底层c++)去执行相应的事情发起指令到系统去做线程调度,系统调度CPU,将线程启动信息返回给jvm,然后响应回给Java中。如下图:
线程会在run方法执行结束后终止
stop()
方法终止线程。public class TestDemo extends Thread{
@Override
public void run() {
//线程会执行的指令
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Come in");
}
public static void main(String[] args) {
TestDemo testDemo = new TestDemo();
testDemo.start();
testDemo.stop(); //不建议 强制终止这个线程。
//发送终止通知
}
}
interrupt()
告知线程终止public class InterruptDemo02 implements Runnable {
@Override
public void run() {
// 判断线程是否已经被中断
while (!Thread.currentThread().isInterrupted()) { //false
try {
TimeUnit.SECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
//可以不做处理,
//继续中断 ->
Thread.currentThread().interrupt(); //再次中断
//抛出异常。。
}
}
System.out.println("processor End");
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new InterruptDemo02());
t1.start();
Thread.sleep(1000);
t1.interrupt(); // 中断线程
//Thread.interrupted() ;//复位
}
}
总结:
Thread.currentThread().isInterrupted()
的状态来对线程做操作sleep()
、join()
、wait()
方法都会抛出InterruptedException
的异常c++对线程状态设置源码:
void os::interrupt(Thread*thread){
assert(Thread::current()==thread||Threads_lock->owned_by_self(),
"possibility of dangling Thread pointer");
OSThread*osthread=thread->osthread();
if(!osthread->interrupted()){
osthread->set_interrupted(true); //设置一个中断状态
// More than one thread can get here with the same value of osthread,
// resulting in multiple notifications. We do, however, want the store
// to interrupted() to be visible to other threads before we execute
unpark().
OrderAccess::fence();
ParkEvent*const slp=thread->_SleepEvent; //如果是sleep中,唤醒
if(slp!=NULL)slp->unpark();
}
// For JSR166. Unpark even if interrupt status already was set
if(thread->is_Java_thread())
((JavaThread*)thread)->parker()->unpark();
ParkEvent*ev=thread->_ParkEvent;
if(ev!=NULL)ev->unpark();
}
以下文章补充:interrupt的知识、interrupt方法