main_thread: 主线程专门用来处理用户的操作(处理UI)。
work_thread: 做下载等工作。
核心数、线程数: 目前主流 CPU 都是多核的。增加核心数目就是为了增加线程数,因为操作系统是通过线程来执行任务的,一般情况下它们是 1:1 对应关系,也 就是说四核 CPU 一般拥有四个线程。但Intel 引入超线程技术后,使核心数与线程 数形成 1:2 的关系
进程是程序运行资源分配的最小单位:
进程是操作系统进行资源分配的最小单位,其中资源包括:CPU、内存空间、 磁盘 IO 等,同一进程中的多条线程共享该进程中的全部系统资源,而进程和进程 之间是相互独立的。进程是具有一定独立功能的程序关于某个数据集合上的一次 运行活动,进程是系统进行资源分配和调度的一个独立单位。
进程是程序在计算机上的一次执行活动。当你运行一个程序,你就启动了一 个进程。显然,程序是死的、静态的,进程是活的、动态的。进程可以分为系统进程和用户进程。凡是用于完成操作系统的各种功能的进程就是系统进程,它们就 是处于运行状态下的操作系统本身,用户进程就是所有由你启动的进程。
线程是 CPU 调度的最小单位,必须依赖于进程而存在:
线程是进程的一个实体,是 CPU 调度和分派的基本单位,它是比进程更小的、 能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其 他的线程共享进程所拥有的全部资源。
cpu只管线程,进程由操作系统调度来管。
一个进程至少有一个线程,或多个线程。
如果一个进程,还有一个线程没有杀掉那么进程还存活(线程依附进程)。
线程代表干活人数,主频代表干活能力强弱。
服务器(24线程)的线程越多越好,打游戏看主频睿频。
CPU时间片轮转机制,一种算法,这种算法就叫做RR调度。
Erlang 之父 Joe Armstrong 的画图解释:
并发:两个队列交替使用一台咖啡机。
并行:两个队列同时使用两台咖啡机。
串行:一个队列使用一个咖啡机,只有前面的人用完才能轮到后面的人用(前面人去上厕所也要等他先用完)。
线程们能被多个cpu执行就是并行。
线程们被一个cpu轮流切换执行就是并发。
并发也是吞吐量(10s内服务器的吞吐量,和时间有关系)。
充分利用 CPU 的资源:
如果设计一个多线程的程序的话,那它就可以同时在多个 CPU 的多个核的多个线程上跑,可以充分地 利用 CPU,减少 CPU 的空闲时间,发挥它的运算能力,提高并发量。
加快响应用户的时间
下载时,多开几个线程去下载。
浏览器在加载你的页面的时候就会多开几个线程去加载你的页面资源,提升网 站的响应速度。
可以使你的代码模块化,异步化,简单化
给用户发送短信、邮件这两个步骤独立为单独的模块,并交给其他线程去执行。 这样既增加了异步的操作,提升了系统性能,又使程序模块化,清晰化和简单化。
注意事项: 不要CPU过累。
进程里面 new Thread() 每一次都开辟栈空间至少1MB.。如果new1000次 result:耗费1G多的内存)
查看运行线程:
public static void main(String[] args) {
//java服务器
//监控jvm虚拟机里面线程的信息,当前main运行线程的信息
/*虚拟机线程管理的借口*/
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
/*取得线程信息*/
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false,false);
for (ThreadInfo threadInfo : threadInfos) {
System.out.println("["+threadInfo.getThreadId()+"]"+" "+threadInfo.getThreadName());
}
}
[6] Monitor Ctrl-Break
[5] Attach Listener
[4] Signal Dispatcher
[3] Finalizer
[2] Reference Handler
[1] main
没有GC线程,并不是马上就有GC线程,资源需要回收,JVM才会检测到,启动GC。
public class NewThread {
//第一种方式 实实在在的线程
private static class StudentThread extends Thread {
@Override
public void run() {
super.run();
System.out.println("do work Thread");
}
}
//第二种方式, 任务 ,可以交给Thread.start
private static class PersonThread implements Runnable {
@Override
public void run() {
System.out.println("do work Runnable");
}
}
//第三种方式, 任务 return xxx ,需要Thread调度 Thread.start
//返回String 包装类
private static class WorkerThread implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("do work Callable");
return "run success Callable";
}
}
public static void main(String[] args) {
StudentThread studentThread = new StudentThread();
studentThread.start(); //.start()才能证明这个是线程
//studentThread.run();//这个和线程没有半毛钱关系,就是函数调用
//任务不能运行,需要寄托Thread,Thread才是线程
PersonThread personThread = new PersonThread();
new Thread(personThread).start();
//有返回值 ,任务不能运行,需要寄托Thread,Thread才是线程
WorkerThread workerThread = new WorkerThread();
//new Thread(workerThread); 不能直接丢进去 会报错 需要依附另外的一个类
//可以通过FutureTask来装载
FutureTask<String> stringFutureTask = new FutureTask<>(workerThread);
new Thread(stringFutureTask).start();
try {
System.out.println(stringFutureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
第三种方式Callable的本质是Runnable
第三种方式可以通过FutureTask来装载:
public class FutureTask<V> implements RunnableFuture<V> {
...}
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
.start():
public synchronized void start() {
if (this.threadStatus != 0) {
throw new IllegalThreadStateException();
} else {
this.group.add(this);
boolean var1 = false;
try {
this.start0();
var1 = true;
} finally {
try {
if (!var1) {
this.group.threadStartFailed(this);
}
} catch (Throwable var8) {
}
}
}
}
private native void start0();
native —》 c++ -----》 调用操作系统
只有.start()才能证明是线程,只有.start()才会调用native 调用底层c++调用系统调度等等,最后返回回来调用run()函数,这样走下来才是线程。
thread.run();这个和线程没有半毛钱关系,就是函数调用。
早期提供了一个函数Stop停止线程(暴力行为,永不使用)
要用和谐的方式(最公认的方式): 想办法让run()执行完, end thread最和谐
public class EndThreadTest {
private static class UseThread extends Thread {
@Override
public void run() {
super.run();
String name = Thread.currentThread().getName();
while(true) {
System.out.println(name + "=== is run");
}
}
}
public static void main(String[] args) throws InterruptedException {
UseThread useThread = new UseThread();
useThread.start();
//休眠
Thread.sleep(10);//给它10毫秒的时间打印
//给run发了个信号,run听不听话是另一回事
useThread.interrupt();//发起中断信号,如果能够停止下来,和暴力有什么区别,停不下来
}
}
修改一下run(),while(!isInterrupted())
private static class UseThread extends Thread {
@Override
public void run() {
super.run();
String name = Thread.currentThread().getName();
while(!isInterrupted()) {
System.out.println(name + "=== is run" + isInterrupted());
}
System.out.println("flag: " + isInterrupted());
}
}
......
Thread-0=== is runfalse
Thread-0=== is runfalse
Thread-0=== is runfalse
Thread-0=== is runfalse
Thread-0=== is runfalse
flag: true
这种方式就是和谐的方式
如果线程是继承Runnable实现的:
private static class UseThread implements Runnable {
@Override
public void run() {
String name = Thread.currentThread().getName();
while(!Thread.currentThread().isInterrupted()) {
System.out.println(name + "=== is run" + Thread.currentThread().isInterrupted());
}
System.out.println("flag: " + Thread.currentThread().isInterrupted());
}
}
public static void main(String[] args) throws InterruptedException {
UseThread useThread = new UseThread();
Thread thread = new Thread(useThread);
thread.start();
//休眠
Thread.sleep(10);//给它10毫秒的时间打印
//给run发了个信号,run听不听话是另一回事
thread.interrupt();//发起中断信号,如果能够停止下来,和暴力有什么区别,停不下来
}