线程打个比方来说就是,一个人在一生中,不停的在做呼吸运动,血液循环,细胞修复,激素分泌等运动,这些运动都是同时进行的,并不是得先做完呼吸运动后才开始血液循环,这种同时执行多个操作的思想,在Java中被称为并发,而将并发完成的每一个事件就称为线程。
专业一点的术语就是:
线程(Thread)是操作系统能够进行
运算调度的最小单位
。它被包含在进程之中
,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程
,每条线程并行执行不同的任务。
直白地讲,进程就是应用程序的启动实例。比如我们运行一个游戏,打开一个软件,就是开启了一个进程 (进程是系统中正在运行的一个程序,程序一旦运行就是进程)。
专业一点的术语就是:
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行
资源分配和调度的基本单位
,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器
。程序是指令、数据及其组织形式的描述,进程是程序的实体
。
1,管道 2,消息队列 3,共享内存 4,信号量 5,Socket
一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程。
协程(Coroutines)是一种
比线程更加轻量级
的存在,正如一个进程可以拥有多个线程一样,一个线程可以拥有多个协程
。协程不是被操作系统内核所管理
的(线程被操作系统调度),而是完全由程序所控制
,也就是在用户态执行。这样带来的好处是性能大幅度的提升,因为不会像线程切换那样消耗资源
线程 | 进程 | |
---|---|---|
单位 | 系统运算调度的最小单位 |
系统资源分配和调度的基本单位 |
地址空间 | 包含在进程的地址空间 中 |
有自己的内存地址空间 |
资源开销 | 系统开销较小 | 系统开销较大 |
资源共享 | 共享所在进程 的地址空间和其它资源 |
进程之间不能共享资源 |
通信 | 线程中通信较为简单 | 进程中通信比较复杂 |
稳壮性 | 低 | 高 |
继承(extends)Thread类,重写run方法,后进行start()进行启动
class Thread1 extends Thread {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println("我是" + Thread.currentThread().getName() + ",现在执行第" + i + "次");
}
}
}
public class MyThread {
public static void main(String[] args) {
Thread myThread = new Thread1(); // 继承可以这样new出来
myThread.setName("Thread1");
myThread.start();
for (int i = 1; i <= 10; i++) {
System.out.println("我是" + Thread.currentThread().getName() + ",现在执行第" + i + "次");
}
}
}
我的运行结果如下,你们的结果不一定是和我的一样的:
我是main,现在执行第1次
我是Thread1,现在执行第1次
我是main,现在执行第2次
我是main,现在执行第3次
我是main,现在执行第4次
我是Thread1,现在执行第2次
我是main,现在执行第5次
我是Thread1,现在执行第3次
我是Thread1,现在执行第4次
我是Thread1,现在执行第5次
我是main,现在执行第6次
我是main,现在执行第7次
我是main,现在执行第8次
我是main,现在执行第9次
我是Thread1,现在执行第6次
我是Thread1,现在执行第7次
我是Thread1,现在执行第8次
我是Thread1,现在执行第9次
我是Thread1,现在执行第10次
我是main,现在执行第10次
因为这和操作系统的调度有关系,由操作系统决定什么时候调度线程1,什么时候调度Main线程。
实现Runnable接口,重写run()方法,然后通过代理Thread来调用start()来启动
class Thread2 implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println("我是" + Thread.currentThread().getName() + ",现在执行第" + i + "次");
}
}
}
public class MyThread {
public static void main(String[] args) {
Thread myThread2 = new Thread(new Thread2()); //实现接口需要这样new Thread(实现的类)
myThread2.setName("Thread2");
myThread2.start();
for (int i = 1; i <= 10; i++) {
System.out.println("我是" + Thread.currentThread().getName() + ",现在执行第" + i + "次");
}
}
}
我的运行结果如下,你们的结果不一定是和我的一样的:
我是main,现在执行第1次
我是main,现在执行第2次
我是Thread2,现在执行第1次
我是main,现在执行第3次
我是Thread2,现在执行第2次
我是main,现在执行第4次
我是Thread2,现在执行第3次
我是main,现在执行第5次
我是Thread2,现在执行第4次
我是main,现在执行第6次
我是Thread2,现在执行第5次
我是main,现在执行第7次
我是Thread2,现在执行第6次
我是main,现在执行第8次
我是Thread2,现在执行第7次
我是main,现在执行第9次
我是Thread2,现在执行第8次
我是main,现在执行第10次
我是Thread2,现在执行第9次
我是Thread2,现在执行第10次
实现Callable接口,重写call()方法,通过代理Thread来接收FutureTask对象并调用start()启动
class Thread3 implements Callable<Object> {
@Override
public Object call() throws Exception { //有异常会抛出
for (int i = 1; i <= 10; i++) {
System.out.println("我是" + Thread.currentThread().getName() + ",现在执行第" + i + "次");
}
return System.currentTimeMillis();
}
}
public class MyThread {
public static void main(String[] args) {
FutureTask<Object> ft = new FutureTask<>(new Thread3()); // 需要用到FutureTask<>
Thread myThread3 = new Thread(ft);
myThread3.setName("Callable");
myThread3.start();
try {
Object _return = ft.get(); //获取返回值
System.out.println("获取到返回值的信息为:" + _return);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
for (int i = 1; i <= 10; i++) {
System.out.println("我是" + Thread.currentThread().getName() + ",现在执行第" + i + "次");
}
}
}
我的运行结果如下,你们的结果可能是和我的一样的:
我是Callable,现在执行第1次
我是Callable,现在执行第2次
我是Callable,现在执行第3次
我是Callable,现在执行第4次
我是Callable,现在执行第5次
我是Callable,现在执行第6次
我是Callable,现在执行第7次
我是Callable,现在执行第8次
我是Callable,现在执行第9次
我是Callable,现在执行第10次
获取到返回值的信息为:1586414586808
我是main,现在执行第1次
我是main,现在执行第2次
我是main,现在执行第3次
我是main,现在执行第4次
我是main,现在执行第5次
我是main,现在执行第6次
我是main,现在执行第7次
我是main,现在执行第8次
我是main,现在执行第9次
我是main,现在执行第10次
通过new FutureTask<>(new Thread3()).get()来获取线程结束后的返回值。
■ 三者对比总结:
线程的生命周期包含5个阶段,包括:新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、销毁(Dead)。
sleep( )
使线程在一定的时间内进入阻塞状态,不能得到cpu时间,但不会释放锁资源。指定的时间一过,线程重新进入可执行状态。wait( )
使线程进入阻塞状态,同时释放自己占有的锁资源,和notify( )搭配使用suspend( )
(ps:JDK1.2之后已经废除) 使线程进入阻塞状态,并且不会自动恢复,必须其对应的resume( )被调用,才能使线程重新进入可执行状态阻塞式I/O方法(Input/Output)
,在该方法返回之前,该线程被阻塞当一个线程通过new关键字创建之后
,该线程就处于新建状态
,此时仅由虚拟机为其分配了内存,但是该线程的执行体并不会执行。
调用start()
方法来启动线程时,该线程就处于就绪状态
,此时该线程可以跟其他线程一起运行。
直接调用run()
方法的话,会被当作一个普通的函数
调用,程序中仍然只有主线程这一个线程
就跟普通的方法没什么区别了,会按照代码顺序进行运行,同时也就没有多线程的效果了。
别急着了解守护线程,在了解它之前,先来了解一下JVM什么情况下能正常退出?(JVM的垃圾回收线程其实就是一个守护线程)下面截了一段JDK官方文档的话:
The Java Virtual Machine exits when the only threads running are all daemon threads.
翻译成中文就是:当 JVM 中不存在任何一个正在运行的非守护线程时,则 JVM 进程即会退出,换句话说就是:如果有一个线程A在线程B里面跑,A不是B的守护线程,那么在线程B跑完的时候,并不会退出JVM,因为线程A是非守护线程,所以程序还是会继续执行A线程
里的代码块,可以看看下边的代码和输出再听我讲解下:
class ThreadA implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println("我是线程A,现在执行第" + i + "次");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("我是线程A,我也结束了我罪恶的一生");
}
}
class ThreadB implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("我是线程B,现在执行第" + i + "次");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 在线程B开启线程A
Thread threadA = new Thread(new ThreadA());
//这里先注释掉 则A线程不是B线程的守护线程
// threadA.setDaemon(true);
threadA.start();
System.out.println("我是ThreadB,我结束了我罪恶的一生");
}
}
public class MyThread {
public static void main(String[] args) {
Thread threadB = new Thread(new ThreadB());
threadB.start();
}
}
打印结果如下:
我是线程B,现在执行第1次
我是线程B,现在执行第2次
我是线程B,现在执行第3次
我是线程B,现在执行第4次
我是线程B,现在执行第5次
我是ThreadB,我结束了我罪恶的一生
我是线程A,现在执行第1次
我是线程A,现在执行第2次
我是线程A,现在执行第3次
我是线程A,现在执行第4次
我是线程A,现在执行第5次
我是线程A,现在执行第6次
我是线程A,现在执行第7次
我是线程A,现在执行第8次
我是线程A,现在执行第9次
我是线程A,现在执行第10次
我是线程A,我也结束了我罪恶的一生
这是没有将线程A设置成B的守护线程的打印,将一个线程设置成守护线程的方法也很简单,Thread.setDaemon(true)
就可以将该Thread设置成守护线程,在这时候,我在线程B中将线程A设置成守护线程,threadA.setDaemon(true)
,这时再来看看打印结果:
我是线程B,现在执行第1次
我是线程B,现在执行第2次
我是线程B,现在执行第3次
我是线程B,现在执行第4次
我是线程B,现在执行第5次
我是ThreadB,我结束了我罪恶的一生
我是线程A,现在执行第1次
可以看到当线程B结束时,线程A在没有打印完的情况下就终止了,不过关闭线程B的时间还是会让线程A走一段时间,不过相对没设置守护线程,如果线程A中的循环是死循环
,它就能很好的退出程序,并且守护线程也会被回收。
守护线程拥有自动结束自己生命周期的特性,而非守护线程不具备这个特点。
JVM 中的垃圾回收线程就是典型的守护线程,如果说不具备该特性,会发生什么呢?
当 JVM 要退出时,由于垃圾回收线程还在运行着,导致程序无法退出,这就很尴尬了!!!由此可见,守护线程的重要性了。
通常来说,守护线程经常被用来执行一些后台任务,但是呢,你又希望在程序退出时,或者说 JVM 退出时,线程能够自动关闭,此时,守护线程是你的首选。
一般情况下,线程都是执行完毕后自动结束死亡的,但有时我们却想手动关闭停止一个线程,那该怎么操作呢,比如关闭正在执行的定时器,因为一般是通过while(true)来不断判断时间,然后执行指定任务。
这时我们可以通过一个条件判断
(eg:isStop)他是否应该要停止:
class ThreadA implements Runnable{
// 是否结束,默认为false
private boolean isStop=false;
@Override
public void run() {
int timeMills = 10;
while (!isStop){
System.out.println("距离结束还剩下:" + timeMills + "秒");
try {
Thread.sleep(1000); //阻塞线程,休眠1s
} catch (InterruptedException e) {
e.printStackTrace();
}
// 这里其实只用timeMills--就可以了,因为它减不到0,在本程序中
//timeMills--;
if(timeMills--==0){
break;
}
}
System.out.println("done");
}
public void stopNow(){
this.isStop = true;
}
}
public class MyThread {
public static void main(String[] args) {
ThreadA thread = new ThreadA();
new Thread(thread).start();
try {
// 让main线程休眠5s,ThreadA线程仍在运行,只是在sleep()这里卡住5s后再运行下边的结束方法
System.out.println(Thread.currentThread().getName());
Thread.sleep(5000);
// 结束线程
thread.stopNow();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
打印结果如下:
main
距离结束还剩下:10秒
距离结束还剩下:9秒
距离结束还剩下:8秒
距离结束还剩下:7秒
距离结束还剩下:6秒
done
【正常的话是从10秒一直打印到1秒,留意打印main上边的那块注释。】
当然早期
是可以通过stop()
方法来停止线程的,但由于stop强制停止
的特性(立刻释放所有监视器monitors),可能会导致一系列难以处理的问题,故最新java版本stop方法已不可用
(ps:貌似现在有个interrupt
方法和isInterrupted()
方法也可以将线程停止,不过只能使用new Thread(){@Override}内部类来定义Thread1,然后再在另一个Thread2调用Thread1.interrupt(),然后Thread1判断isInterrupted()
,不过这个interput我也没整明白,试了几次也结束不了…)。
首先查看源码可看到,这里的优先级默认为5,最小为1,最大为10,分别对应:
优先级越大,大概率先执行
class ThreadB implements Runnable {
private int index;
@Override
public void run() {
while (index <= 10) {
System.out.println("我是:"+Thread.currentThread().getName()+",优先级为:"+Thread.currentThread().getPriority());
index++;
}
index=0;
}
}
public class MyThread {
public static void main(String[] args) {
// 声明对象tb
ThreadB tb = new ThreadB();
Thread a = new Thread(tb);
Thread b = new Thread(tb);
Thread c = new Thread(tb);
Thread d = new Thread(tb);
Thread e = new Thread(tb);
a.setPriority(Thread.MIN_PRIORITY); //最小优先级
b.setPriority(Thread.MAX_PRIORITY); //最大优先级
c.setPriority(Thread.NORM_PRIORITY); //默认优先级
d.setPriority(Thread.MAX_PRIORITY); //最大优先级
e.setPriority(Thread.MIN_PRIORITY); //最小优先级
a.start();
b.start();
c.start();
d.start();
e.start();
}
}
程序打印结果如下:
我是:Thread-1,优先级为:10
我是:Thread-3,优先级为:10
我是:Thread-0,优先级为:1
我是:Thread-2,优先级为:5
我是:Thread-0,优先级为:1
我是:Thread-3,优先级为:10
我是:Thread-4,优先级为:1
我是:Thread-1,优先级为:10
我是:Thread-4,优先级为:1
我是:Thread-3,优先级为:10
我是:Thread-0,优先级为:1
我是:Thread-2,优先级为:5
我是:Thread-3,优先级为:10
我是:Thread-4,优先级为:1
我是:Thread-1,优先级为:10
我是:Thread-4,优先级为:1
我是:Thread-3,优先级为:10
我是:Thread-3,优先级为:10
我是:Thread-3,优先级为:10
我是:Thread-3,优先级为:10
我是:Thread-3,优先级为:10
我是:Thread-3,优先级为:10
我是:Thread-2,优先级为:5
我是:Thread-4,优先级为:1
我是:Thread-1,优先级为:10
我是:Thread-1,优先级为:10
我是:Thread-1,优先级为:10
我是:Thread-1,优先级为:10
我是:Thread-1,优先级为:10
我是:Thread-1,优先级为:10
我是:Thread-1,优先级为:10
我是:Thread-1,优先级为:10
我是:Thread-1,优先级为:10
我是:Thread-4,优先级为:1
我是:Thread-2,优先级为:5
我是:Thread-2,优先级为:5
我是:Thread-4,优先级为:1
我是:Thread-4,优先级为:1
我是:Thread-4,优先级为:1
我是:Thread-4,优先级为:1
我是:Thread-2,优先级为:5
我是:Thread-4,优先级为:1
我是:Thread-2,优先级为:5
我是:Thread-2,优先级为:5
我是:Thread-4,优先级为:1
我是:Thread-4,优先级为:1
我是:Thread-4,优先级为:1
我是:Thread-4,优先级为:1
我是:Thread-4,优先级为:1
我是:Thread-4,优先级为:1
我是:Thread-4,优先级为:1
我是:Thread-4,优先级为:1
我是:Thread-4,优先级为:1
我是:Thread-4,优先级为:1
我是:Thread-4,优先级为:1
从结果可以看出,并不是优先级最高就一定最先执行,优先级低的也可能先执行,只是概率上是优先级大的先执行。
⚪某种意义上说可以让线程有顺序的执行,同时若在当前ThreadA线程上,调用了ThreadB.join()方法,那么会先把ThreadB线程先完成,后再继续执行ThreadA,前提是ThreadB.join()完之后,下边没有其它线程的join()方法,如果还有其它线程的join()方法,则继续执行其它线程。
代码如下:
public class MyThread {
public static void main(String[] args) {
Thread t1 = new Thread(){
private int index;
@Override
public void run() {
while (index <= 5) {
System.out.println("我是Thread1,index = " + index + " ");
index++;
}
}
};
Thread t2 = new Thread(){
private int index;
@Override
public void run() {
while (index <= 5) {
try {
t1.join(); //这里让t1线程插队
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是Thread2,index = " + index + " ");
index++;
}
}
};
Thread t3 = new Thread(){
private int index;
@Override
public void run() {
while (index <= 5) {
try {
t2.join(); //这里让t1线程插队
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是Thread3,index = " + index + " ");
index++;
}
}
};
t1.start();
t2.start();
t3.start();
}
}
因为在线程t2中,让t1线程插队了,然后再线程t3中,让t2插队了,所以不管一开始是t2还是t3线程执行,若是t3先执行,t2插队执行,插队后,t1又插队执行,所以t1线程必定是第一个执行的,然后就是到t2执行,再到t3,打印结果和预期一致,如下:
我是Thread1,index = 0
我是Thread1,index = 1
我是Thread1,index = 2
我是Thread1,index = 3
我是Thread1,index = 4
我是Thread1,index = 5
我是Thread2,index = 0
我是Thread2,index = 1
我是Thread2,index = 2
我是Thread2,index = 3
我是Thread2,index = 4
我是Thread2,index = 5
我是Thread3,index = 0
我是Thread3,index = 1
我是Thread3,index = 2
我是Thread3,index = 3
我是Thread3,index = 4
我是Thread3,index = 5
若将代码改一改,在t3线程让t1插队,而不让t2插队,想一想,结果会是什么样的呢?
没错,t1还是会最先执行,而t2,t3则会按照系统的调度来执行:
我是Thread1,index = 0
我是Thread1,index = 1
我是Thread1,index = 2
我是Thread1,index = 3
我是Thread1,index = 4
我是Thread1,index = 5
我是Thread3,index = 0
我是Thread3,index = 1
我是Thread2,index = 0
我是Thread3,index = 2
我是Thread2,index = 1
我是Thread3,index = 3
我是Thread2,index = 2
我是Thread3,index = 4
我是Thread2,index = 3
我是Thread3,index = 5
我是Thread2,index = 4
我是Thread2,index = 5
当然,可以把定义在内部的join删除掉,然后这样写也可以的噢:
⚪故名思意,就是睡觉,你想睡多久,就往括号里边传入你想睡的时间,单位为ms,使用该方法会将当前线程状态变为阻塞状态
,使得该线程不会获得执行操作,即使系统中没有其它线程,该线程仍然是处于阻塞暂停状态(咋瓦鲁多~),当然,如果线程在睡眠状态被中断,将会抛出IterruptedException
中断异常。
注意
:
1、线程睡眠到期自动苏醒,并返回到可运行状态(就绪),不是运行状态。
2、sleep()中指定的时间是线程不会运行的最短时间,sleep方法不能作为精确的时间控制。
3、sleep()是静态方法,只能控制当前正在运行的线程。
4、sleep()方法并不会释放锁
⚪译为线程让步
,顾名思义,就是说当一个线程使用了这个方法之后,它就会把自己CPU执行的时间让掉,让自己或者其它的线程运行,注意是让自己或者其他线程运行,并不是单纯的让给其他线程。
它能让当前线程由“运行状态”进入到“就绪状态
”,从而让其它具有相同优先级的等待线程获取执行权;但是,并不能保证在当前线程调用yield()之后,其它具有相同优先级的线程就一定能获得执行权;也有可能是当前线程又进入到“运行状态”继续运行!
举个例子:一帮朋友在排队上公交车,轮到Yield的时候,他突然说:我不想先上去了,咱们大家来竞赛上公交车。然后所有人就一块冲向公交车,
有可能是其他人先上车了,也有可能是Yield先上车了。
但是线程是有优先级的,优先级越高的人,就一定能第一个上车吗?这是不一定的,优先级高的人仅仅只是第一个上车的概率大了一点而已,
最终第一个上车的,也有可能是优先级最低的人。并且所谓的优先级执行,是在大量执行次数中才能体现出来的。
代码如下:
class ThreadA extends Thread {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("ThreadA|||" + i);
Thread.yield(); //-------这里用了yield--------
}
}
}
class ThreadB extends Thread {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("ThreadB---" + i);
Thread.yield(); //-------这里用了yield--------
}
}
}
public class TestYield {
public static void main(String[] args) {
Thread threadA = new ThreadA();
Thread threadB = new ThreadB();
// 设置优先级:MIN_PRIORITY最低优先级1;NORM_PRIORITY普通优先级5;MAX_PRIORITY最高优先级10
threadA.setPriority(Thread.MAX_PRIORITY); // 相同大小优先级
threadB.setPriority(Thread.MAX_PRIORITY);
threadA.start();
threadB.start();
}
}
这里注意的是,两个线程优先级都相同,都用了yield()进行让步,所以说线程的运行其实是看系统的调度,打印如下:
ThreadA|||0
ThreadB—0
ThreadA|||1
ThreadB—1
ThreadA|||2
ThreadB—2
ThreadA|||3
ThreadB—3
ThreadA|||4
ThreadB—4
ThreadA|||5
ThreadB—5
ThreadA|||6
ThreadB—6
ThreadA|||7
ThreadB—7
ThreadA|||8
ThreadB—8
ThreadA|||9
ThreadB—9
ThreadA|||10
ThreadB—10
ThreadA|||11
ThreadB—11
ThreadA|||12
ThreadB—12
ThreadA|||13
ThreadB—13
ThreadA|||14
ThreadB—14
ThreadA|||15
ThreadB—15
ThreadA|||16
ThreadB—16
ThreadA|||17
ThreadB—17
ThreadA|||18
ThreadB—18
ThreadA|||19
ThreadB—19
然后我就在想,既然是让步的话,说明可以提高另一个线程的执行
?我就想着让线程B获得最大优先级
,线程A获得最小优先级,然后在线程A中,在使用yield()方法进行让步
,会不会使得线程B更大概率先执行呢?改了两处地方:
执行打印结果:
第一次打印 | 第二次打印 |
---|---|
ThreadB | ThreadA |
ThreadA | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadA | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadB |
ThreadB | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
ThreadA | ThreadA |
emmm果真有点效果,测试了五六次,大部分都是B执行较A更早,不过也有小概率A执行完,其中有两次都是A先执行完再到B的,不过貌似可以用这种方法再提高
线程的优先级。
最经典的例子是生产者/消费者模式
,即若干个生产者线程向队列中系欸如数据,若干个消费者线程从队列中消费数据。这里先不贴代码了,等到时有时间再弄个相关博客^^
篇幅较长的一篇关于线程的知识介绍,当然肯定还有很多要补充的,改天有时间再添加上一些内容,相信看完后的你肯定有了不少的收货,不妨将收货用到实践中,多动手,这样记住得比较牢固。