啥是多线程?跟进程又是啥关系?
比方说:我去洗手,洗完手去吃饭。
进程(Processor)
洗手跟吃饭是两个进程。
线程(Thread)
在洗手的进程里,我同时听歌,还唱歌。那这里洗手是一个进程,听歌跟唱歌是两个线程。
在吃饭的进程里,我同时听歌,还唱歌。那这里吃饭是一个进程,听歌跟唱歌是两个线程。
吃饭跟洗手两个进程之间的线程互不干扰,同个进程之间的线程存在锁、等待、唤醒等等等机制。
多线程:同一个进程内做多件事,每件事是一个线程
这里创建一个普通java项目。
单线程示例
以吃饭为例,只有听完歌才能唱歌,无法边听边唱。
class Main
public class Main {
/**
* 吃饭
* @param args
*/
public static void main(String[] args) {
Song song = new Song();
while (!song.listenIsZero())
song.doThing("listen") ;
while (!song.singIsZero())
song.doThing("sing") ;
System.out.println("执行完成!");
}
}
class Song
public class Song {
// 待唱的歌曲数量
private int singNum = 5 ;
// 待听的歌曲数量
private int listenNum = 5 ;
public boolean singIsZero(){
return singNum == 0 ;
}
public boolean listenIsZero(){
return listenNum == 0 ;
}
public void doThing(String thing){
switch (thing){
case "sing" : doSing(); break;
case "listen" : doListen(); break;
}
}
public void doSing(){
try {
// 唱歌需要时间,加时间能体现多线程的效果
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("唱了一首歌,剩余:" + singNum-- +"首未唱");
if (singIsZero()) System.out.println("唱完了!");
}
public void doListen(){
try {
// 听歌需要时间,加时间能体现多线程的效果
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("听了一首歌,剩余:" + listenNum-- +"首未听");
if (listenIsZero()) System.out.println("听完了!");
}
}
执行结果
多线程示例(继承Thread类)
可以在吃饭的进程里,边听歌边唱歌。同时进行。
创建一个类负责听歌或者唱歌,继承Thread,重写run函数。
建立两个线程,都start之后可以观察到两个线程同时调用doThing函数。
class Main
public class Main {
/**
* 吃饭
* @param args
*/
public static void main(String[] args) {
// 单线程示例
/*Song song = new Song();
while (!song.listenIsZero())
song.doThing("listen") ;
while (!song.singIsZero())
song.doThing("sing") ;*/
// 多线程示例
SongThread listen = new SongThread("listen", new Song());
SongThread sing = new SongThread("sing", new Song());
// 启动两个线程
listen.start();
sing.start();
System.out.println("执行完成!");
}
}
class SongThread
public class SongThread extends Thread{
private Song song ;
private String thing ;
public SongThread(String thing, Song song){
this.song = song;
this.thing = thing;
}
public void run(){
switch (thing){
case "listen" : while (!song.listenIsZero()) song.doListen(); break;
case "sing" : while (!song.singIsZero()) song.doSing(); break;
}
}
}
执行结果
多线程示例(实现Runnable接口)
创建一个类实现Runnable接口,然后new Thread的时候将实现类传参之后start。
Thread与Runnable的关系:Thread类实现了Runnable接口。
class Main
public class Main {
/**
* 吃饭
* @param args
*/
public static void main(String[] args) {
// 单线程示例
/*Song song = new Song();
while (!song.listenIsZero())
song.doThing("listen") ;
while (!song.singIsZero())
song.doThing("sing") ;*/
/*// 多线程示例 Thread
SongThread listen = new SongThread("listen", new Song());
SongThread sing = new SongThread("sing", new Song());
// 启动两个线程
listen.start();
sing.start();
System.out.println("执行完成!");*/
// 多线程示例 实现Runnable接口
SongRunnable listen = new SongRunnable("listen", new Song());
SongRunnable sing = new SongRunnable("sing", new Song());
// 启动两个线程
new Thread(listen).start();
new Thread(sing).start();
}
}
class SongRunnable
public class SongRunnable implements Runnable{
private Song song ;
private String thing ;
public SongRunnable(String thing, Song song){
this.song = song;
this.thing = thing;
}
public void run(){
switch (thing){
case "listen" : while (!song.listenIsZero()) song.doListen(); break;
case "sing" : while (!song.singIsZero()) song.doSing(); break;
}
}
}
执行结果
java多线程-初探(二)
实际业务应用场景举例
1.后台需要定时给数据库100w个用户发送提醒邮件。
启动两个线程分别给50w个用户发邮件。
2.不影响用户情况下记录用户操作日志(异步)
启动一个线程去单独执行记录日志的操作。