去年学习操作系统的时候,提到进程之间会抢占cpu时间片,实现线程的并发。其实想象起来可能有些理想,感觉进程们都会乖乖的去按照时间片轮转来轮着执行,可是事实是,他们之间的竞争是异常的激烈。我们用三个线程买票的故事说明一下,其实进程之间也差不多。
我们用一段代码来演示一下,这段代码引用慕课网视频《细说多线程之Thread VS Runnable》,感兴趣的可以去看一下。
我们用一段代码来演示一下,这段代码引用慕课网视频《细说多线程之Thread VS Runnable》,感兴趣的可以去看一下。
class MyThread1
implements
Runnable{
int ticketCount
=
5;//表示剩余票数
@
Override
public
void run() {
while(ticketCount
>
0){
ticketCount
--;
System.out.println(
Thread.currentThread().getName()
+
"卖了一张票,还剩"
+ ticketCount
+
"张票");
}
}
}
public
class TicketRannable {
public
static
void main(
String[] args) {
MyThread1 mt
=
new MyThread1();
Thread mt1
=
new
Thread(mt,
"窗口1");//创建窗口买票线程
Thread mt2
=
new
Thread(mt,
"窗口2");
Thread mt3
=
new
Thread(mt,
"窗口3");
mt1.start();//启动线程
mt2.start();
mt3.start();
}
}
贴一下执行结果:
窗
口1
卖
了
一
张
票
,
还
剩4
张
票
窗
口3
卖
了
一
张
票
,
还
剩2
张
票
窗
口2
卖
了
一
张
票
,
还
剩3
张
票
窗
口3
卖
了
一
张
票
,
还
剩0
张
票
窗
口1
卖
了
一
张
票
,
还
剩1
张
票
有没有看到三个凶残的线程呢?好,不明白我来解释一下。上面代码:
先是,实现Runnable接口来定义一个买票的线程类,里面有一个表示剩余票数的变量,run()方法的逻辑很简单,每执行一次,票数减一,输出剩余票数。
然后,在main方法中创建三个窗口买票的线程,然后启动他们。
ok,执行结果是4,2,3,0,1???为什么不是4,3,2,1,0呢?这就是线程之间在进行cpu资源的抢占的结果,解释一下:当窗口1抢到cpu之后执行了一次run()方法;接着,窗口2抢到了cpu,但是窗口2实在是弱爆了,还没执行完run()方法,只执行了一句ticketCount--,就被窗口3把cpu抢去了,然后窗口3执行了一次run()方法,接着才把cpu让给窗口2让他来输出,那么下面的也是类似了。
让我们对以上三个线程的综合表现做一个点评:
窗口1:业务中规中矩,轮着他了买一张,被抢了,乖乖让出cpu
窗口2:业务最差,有明显的偷懒痕迹。
窗口3:打了鸡血的窗口3,两次业务都是提前完成,碾压窗口1,2
排名:窗口3 > 窗口1 > 窗口2。
好了,线程的故事到此结束。讲这个的目的,是加深一下对线程同步和并发的理解。
先是,实现Runnable接口来定义一个买票的线程类,里面有一个表示剩余票数的变量,run()方法的逻辑很简单,每执行一次,票数减一,输出剩余票数。
然后,在main方法中创建三个窗口买票的线程,然后启动他们。
ok,执行结果是4,2,3,0,1???为什么不是4,3,2,1,0呢?这就是线程之间在进行cpu资源的抢占的结果,解释一下:当窗口1抢到cpu之后执行了一次run()方法;接着,窗口2抢到了cpu,但是窗口2实在是弱爆了,还没执行完run()方法,只执行了一句ticketCount--,就被窗口3把cpu抢去了,然后窗口3执行了一次run()方法,接着才把cpu让给窗口2让他来输出,那么下面的也是类似了。
让我们对以上三个线程的综合表现做一个点评:
窗口1:业务中规中矩,轮着他了买一张,被抢了,乖乖让出cpu
窗口2:业务最差,有明显的偷懒痕迹。
窗口3:打了鸡血的窗口3,两次业务都是提前完成,碾压窗口1,2
排名:窗口3 > 窗口1 > 窗口2。
好了,线程的故事到此结束。讲这个的目的,是加深一下对线程同步和并发的理解。