Java多线程
一、进程与线程的理解
线程总是和进程分不开的,但是说到线程,我们还要先介绍一下进程
1.1 对进程的理解
- 进程:是指在系统中运行的一个应用程序,比如我们用手机打游戏的时候,有时候卡了,手机会提示是否结束应用程序,这个就是进程。电脑也是如此,比如打开一个软件的时候,长时间没有响应,鼠标点一下,电脑就会提示你是否结束应用程序,还有,在电脑上,我们按下ctrl+alt+delete 键找到任务管理器一栏,我们就可以清楚的看到电脑上正在运行中的进程,如下:

1.2 对线程的理解
- 线程:线程就是一个正在执行的进程当中的一个子任务,所以开启一个进程(应用程序)就会进行多个子任务,共同完成任务
1.3 两者差别
两者区别:从上面的图中可以看出每个进程都会占用一定的内存,每个进程所占用的内存在操作系统中都是相互独立的,然后在线程当中,在同一块内存区域,每一个线程可以共享数据,所以线程之间的资源占用比较小
1.4 多线程
把一个线程比喻成一个子任务的话,多线程就是多个任务在同一段时间共同执行,Java中是可以编写多线程的程序的
- 多线程的好处
多线程的最大好处就是可以并发执行多个任务,当某一个任务因为意外终止时,那么就可以创建新的线程继续执行剩下的任务 - 为什么用多线程?
多线程可以极大提高 CPU 的利用率,从而提高电脑运行速度
二、Java实现多线程
2.1 两种实现方法
- 在Java.lang.Thread类(常常用于继承该类来实现线程的操作)
- 在Java.lang.Runnable接口(常用于实现多线程)
接下来,我们就以 泡茶 为例,给大家讲解线程的实现
首先泡茶要经过三个阶段
- 烧水
- 洗杯子
- 倒茶

代码实现:
//进程之前没有 修饰符 public,不然会Java默认为一个方法
class BoilThread extends Thread {//定义烧水的线程
@Override
public void run(){//执行线程,这里用了重写的操作
try {
System.out.println("开始烧开水");
Thread.sleep(10000);//延时函数,10s,基本单位是毫秒
System.out.println("水开了!");
} catch (Exception e) {
// TODO: handle exception
}
}
}
class WashThread extends Thread {//定义洗杯子的线程
@Override
public void run(){
try {
for(int i=1;i<=5;i++){//这里洗五个杯子
System.out.println("开始洗第"+i+"个杯子");
Thread.sleep(1500);
System.out.println("第"+i+"个杯子洗完了");
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
public class MakeTea {
public static void main(String[] args) {
new BoilThread().start();//在主函数中执行线程
new WashThread().start();
}
}
现在大家对 线程 是不是有了更深一点的认识呢?
2.2 Java线程(Thread类)的常用用法
下面介绍一下常用的用法
线程名字可以通过 t.setName() 来设置
优先级可以通过 t.setPriority() 括号里传入1~10的整数即可
延时操作 可以通过 t.sleep() 括号传入整数,单位是毫秒
线程开始 可以同过 t.start(),结束是 t.stop() 等等
在Java 中实现线程,可以直接继承 Thread 类,然后再重写 run 方法,run方法本身不执行任何操作,但是重写之后,我们再执行,就会直接运行run 方法中的内容(详见上面的泡茶 示例)
2.2.1 Thread 的示例
Thread 类直接继承即可,在其中的方法都是静态方法,所以可以直接调用使用
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Thread t=Thread.currentThread();//获取当前运行的线程
t.setName("t1");//给当前线程设置为另一个名字,否则默认为main
System.out.println("当前的线程:"+t);
try {
for (int i = 0; i < 5; i++) {//线程的运行实例
System.out.println("i:"+i);
Thread.sleep(1000);
}
} catch (Exception e) {
// TODO: handle exception
}
}
}

运行的第一行结果如下
方括号中的第一个为我们自定义的姓名,5为这个线程的优先级(优先级是从1~10,5为默认的值),第三个是线程学名。
关于 sleep 与 yield 的解释
这两者都是 Thread 的静态方法,它们的功能都是使当前运行的线程放弃 CPU,但是还是有一些细微的差别
- sleep 给其他线程运行机会,但不考虑其他线程的优先级,而 yield 不会把运行线程的机会留给优先级比自己低的进程
- 线程执行了sleep 就进入了阻塞状态,执行了yield 就进入了就绪状态(操作系统里面有对进程的详细讲解)
- 还有 sleep 在使用的时候 可能会抛出异常,所以需要 补获异常,yield 是没有这个过程的
所以一般情况还是使用 sleep 的情况比较多
2.3 Java线程(Runnable)的常用用法
在 Runnable 中只有 一个 public void run() 的抽象方法
实现 Runnable 接口并在 run() 中实现相对应的方法即可实现线程
Runnable 解决了多继承的问题
这里是把上面的 Thread 实现的代码 用 Runable重新实现了一遍
class MyThread implements Runnable{//实现接口
@Override
public void run() {//重写方法体
// TODO Auto-generated method stub
String strName=Thread.currentThread().getName();
try {
for (int i = 1; i < 11; i++) {
System.out.println("当前线程的名字是:"+strName+" "+i);
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
public class ThreadTest {
public static void main(String[] args) {
Thread t1=new Thread(new MyThread());
t1.setName("t1");//给线程1 设置 名称
Thread t2=new Thread(new MyThread());
t2.setName("t2");
t1.setPriority(8);//给线程1设置优先级
t2.setPriority(6);
System.out.println("t1优先级:"+t1.getPriority());
System.out.println("t2优先级:"+t2.getPriority());
t1.start();//开始线程
t2.start();
}
}
运行结果:
这里的线程执行的次数比较少,所以优先级显示的不是那么明显,改成 运行 50次就可以很快看出来啦
下面是一个实际问题,某电影院有的热映电影还剩 100张票,现在有3个窗口,要同步售票,把票给卖出去(这就是一个比较简单的多线程问题)
这里我们需要两个类来完成
public class SellTicket implements Runnable {
private int ticketCount=100;//定义票为100张电影票
//增加锁对象
private Object obj = new Object();
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
synchronized (obj) {//使用同步锁可以避免出现负数的情况
try {
if(ticketCount>0){
Thread.sleep(100);//睡眠0.1秒
System.out.println(Thread.currentThread().getName()+"正在卖票:"+ticketCount--);
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
}
}
测试类
public class TicketTest {
public static void main(String[] args) {
SellTicket st=new SellTicket();//实例化票的类
Thread t1=new Thread(st, "窗口1");
Thread t2=new Thread(st, "窗口2");
Thread t3=new Thread(st, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
这就是多线程的一个体现
















