一、基础概念
1、CPU核心数和线程数的关系
核心数:线程数=1:1 ;使用了超线程技术后---> 1:2
2、CPU时间片轮转机制
又称RR调度,会导致上下文切换
3、什么是进程和线程
进程:程序运行资源分配的最小单位,进程内部有多个线程,会共享这个进程的资源
线程:CPU调度的最小单位,必须依赖进程而存在。
4、澄清并行和并发
并行:同一时刻,可以同时处理事情的能力
并发:与单位时间相关,在单位时间内可以处理事情的能力
5、高并发编程的意义、好处和注意事项
好处:充分利用cpu的资源、加快用户响应的时间,程序模块化,异步化
存在问题:
线程共享资源,存在冲突;
容易导致死锁;
启用太多的线程,就有搞垮机器的可能
二、认识Java里的线程
1、新启线程的方式
三种实现方式
继承类Thread
实现接口Runnable
实现 接口 Callable
代码如下
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @Auther: BlackKingW
* @Date: 2019/4/14 12:09
* @Description:
*/
public class NewThread {
/*继承自Thread类*/
private static class UseThread extends Thread{
@Override
public void run() {
System.out.println("I am extends Thread");
}
}
/*实现Runnable接口*/
private static class UseRun implements Runnable{
@Override
public void run() {
System.out.println("I am implements Runnable");
}
}
/*实现Callable接口,允许有返回值*/
private static class UseCall implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("I am implements Callable");
return "CallResult";
}
}
public static void main(String[] args)
throws InterruptedException, ExecutionException {
UseThread useThread = new UseThread();
useThread.start();
UseRun useRun = new UseRun();
new Thread(useRun).start();
Thread t = new Thread(useRun);
t.interrupt();
UseCall useCall = new UseCall();
FutureTask<String> futureTask = new FutureTask<>(useCall);
new Thread(futureTask).start();
System.out.println(futureTask.get());
}
}
需要注意的是,实现Callable是不能直接放在线程里使用的,必须使用FutureTask包装之后才能在线程里使用。如果想要获取Callable执行结果的返回值,则需要借助FutureTask 的get方法。
2、线程安全的停止
1、线程自然终止:自然执行完或抛出未处理异常
2、stop(),resume(),suspend()已不建议使用,stop()会导致线程不会正确释放资源,suspend()容易导致死锁。
3、使用interrupt()方法
java线程是协作式,而非抢占式
调用一个线程的interrupt() 方法中断一个线程,并不是强行关闭这个线程,只是跟这个线程打个招呼,将线程的中断标志位置为true,线程是否中断,由线程本身决定。
isInterrupted() 判定当前线程是否处于中断状态。
static方法interrupted() 判定当前线程是否处于中断状态,同时中断标志位改为false。
方法里如果抛出InterruptedException,线程的中断标志位会被复位成false,如果确实是需要中断线程,要求我们自己在catch语句块里再次调用interrupt()。
代码如下
import java.util.concurrent.ExecutionException;
/**
* @Auther: BlackKingW
* @Date: 2019/4/14 12:09
* @Description:
*/
public class DaemonThread {
private static class UseThread extends Thread {
@Override
public void run() {
try {
while (!isInterrupted()) {
System.out.println(Thread.currentThread().getName()
+ " I am extends Thread.");
}
System.out.println(Thread.currentThread().getName()
+ " interrupt flag is " + isInterrupted());
} finally {
System.out.println("...........finally");
}
}
}
public static void main(String[] args) throws InterruptedException,
ExecutionException {
UseThread useThread = new UseThread();
useThread.start();
Thread.sleep(5);
useThread.interrupt();
}
}
3、线程的状态
线程常用方法和线程的状态
线程只有5种状态。整个生命周期就是这几种状态的切换。
run()和start() :run方法就是普通对象的普通方法,只有调用了start()后,Java才会将线程对象和操作系统中实际的线程进行映射,再来执行run方法。
yield() :让出cpu的执行权,将线程从运行转到可运行状态,但是下个时间片,该线程依然有可能被再次选中运行。
线程的优先级
取值为1~10,缺省为5,但线程的优先级不可靠,不建议作为线程开发时候的手段
守护线程
和主线程共死,finally不能保证一定执行,可以使用
Thread.setDaemon(true);
方法将线程设置为守护线程。