翻书:哦,马冬梅
合书:马什么梅?
翻书:哦,马冬梅?
合书:马东什么?
翻书:哦,马冬梅啊
合书:什么东梅?
多线程,很多人听到就头疼的东西(我听到也头疼)但是还是决定准备写下来加深一下理解吧。
一、啥是多线程
首先,先来一点文邹邹的东西,一个程序是一个进程 ,一个进程至少有一个线程,而线程是操作系统可识别的最小执行和调度单位。而多线程是多个线程并发执行。
eg:如果楼下食堂是一个系统的话,你火急火燎的去吃饭,等待(手抖的)阿姨给你打菜,但是楼下的队伍长的出奇,这让你很不开心让来吃饭的人也都很不开心,于是乎食堂老板含泪多招了几位阿姨来一起给你们打菜。这就可以理解为多条线程并发执行任务。
二、如何创建线程
1.一个类继承Thread类,并重写里面的run()方法。
2.一个类去实现Runnable接口,并实现里面的run()方法。
3.创建一个线程池,并线程池中直接获取一个线程。
一般常用的是第二种,因为java只能单继承但是可以多实现
三、代码实例
首先我们设计大家普遍运用的场景:
很前一段时间复联4上映了,那叫一个火啊,其中钢铁侠、美国队长、雷神。。。。差点跑题了。这么火的电影首映当然得靠抢啊,这一天万达影城预售100张票,由三个自助售票机售卖。于是乎我们有了如下代码:
ThreadDemo.java
public class ThreadDemo implements Runnable{
//预售100张
private int tickets = 100;
@Override
public void run() {
while (true) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在售卖第" + (tickets--) + "张票");
}else{
return;
}
}
}
}
SellTicketDemo.java
public class SellTicketDemo {
public static void main(String[] args) {
ThreadDemo demo = new ThreadDemo();
Thread t1 = new Thread(demo,"售票机1号");
Thread t2 = new Thread(demo,"售票机2号");
Thread t3 = new Thread(demo,"售票机3号");
t1.start();
t2.start();
t3.start();
}
}
执行main结果如图:
好像没什么问题,但是这是在我的测试中,实际生活中由于网络原因肯定会出现一点延迟情况,下面我在run方法中添加一丢丢延迟(加100毫秒,很短的延迟了 )
ThreadDemo.java
public class ThreadDemo implements Runnable{
//预售100张
private int tickets = 100;
@Override
public void run() {
while (true) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在售卖第" + (tickets--) + "张票");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
return;
}
}
}
}
结果:
出现了一票多卖的情况,因为延迟的原因导致线程之间的数据没有及时同步导致的。这个时候就需要引入一个同步机制,也就是synchronized关键字
public class ThreadDemo implements Runnable{
//预售100张
private int tickets = 100;
@Override
public void run() {
while (true) {
synchronized (this) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在售卖第" + (tickets--) + "张票");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
return;
}
}
}
}
}
如图已经正常。但是看起来又不像那么正常,感觉售票机2号好像没工作,其实并不是,因为有很大可能在线程1执行run的时候在while里面执行if,这时已经锁住了,线程2和3无法操作,但是当if执行结束后释放锁,但是紧接着第二波的循环过来了,第二波循环到来的比线程2、3获取的快,就会导致执行结果为某一条线程消耗了所有票,结果可能会误导一些人们,其实事实上程序并没错只是其他获取锁没有循环来的快而导致的。可以在if后加上一个短暂延迟,便于测试与理解。
代码实例:
public class ThreadDemo implements Runnable{
private int tickets = 100;
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行run方法");
while (true) {
synchronized (this) {
System.out.println(Thread.currentThread().getName() + "上锁");
if (tickets > 0) {
try {
// 延迟
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在消耗第" + (tickets--) + "条数据");
}else{
System.out.println(Thread.currentThread().getName() + "没数据了");
return;
}
System.out.println(Thread.currentThread().getName() + "即将解锁");
}
try {
//延迟100毫秒让其他线程进入
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class SellTicketDemo {
public static void main(String[] args) {
ThreadDemo demo = new ThreadDemo();
Thread t1 = new Thread(demo,"线程1");
Thread t2 = new Thread(demo,"线程2");
Thread t3 = new Thread(demo,"线程3");
t1.start();
System.out.println("线程1已启动");
t2.start();
System.out.println("线程2已启动");
t3.start();
System.out.println("线程3已启动");
}
}
合书:嗯,马冬梅。