多线程(一)概念、线程
目录
进程、线程、程序
- 进程
- 一个进程可以有多个线程(如视频中听声音,看图像,看弹幕)
-
进程是程序执行的过程
- 进程是系统资源分配的单位
- 一个进程至少有一个线程
- 线程是cpu调度和执行的单位
- 线程
进程
进程创建(三种方式)
方式1:Thread class(重点)
步骤:
- 自定义线程类继承Thread类
- 重写run()方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
代码实例(创建进程)
//线程开启不一定执行,由cpu调度执行
public class TestThread01 extends Thread{
//线程的执行体
public void run(){
//run方法线程体
for(int i=0;i<20;i++){
System.out.println("sxp01:"+i);
}
}
public static void main(String[] args) {
//主线程
//创建一个线程对象
TestThread01 testThread01=new TestThread01();
//调用start()方法开启线程
testThread01.start();
for(int i=0;i<20;i++){
System.out.println("sxp02:"+i);
}
}
}
//输出:
sxp02:0
sxp02:1
sxp02:2
sxp02:3
sxp01:0
sxp02:4
sxp02:5
sxp02:6
sxp02:7
sxp01:1
sxp02:8
sxp01:2
sxp02:9
sxp01:3
sxp02:10
sxp01:4
sxp02:11
sxp01:5
sxp02:12
sxp01:6
sxp01:7
sxp01:8
sxp02:13
sxp01:9
sxp02:14
sxp01:10
sxp01:11
sxp02:15
sxp01:12
sxp02:16
sxp01:13
sxp02:17
sxp02:18
sxp02:19
sxp01:14
sxp01:15
sxp01:16
sxp01:17
sxp01:18
sxp01:19
方式2:Runnable接口(重点)(推荐)
步骤:
- 实现Runnable接口
- 重写run()方法,编写线程执行体
- 启动线程:传入目标对象+Thread对象.start()
- 推荐使用:避免单继承的局限性,方便同一个对象被多个线程使用
代码实例(创建进程)
//创建线程方式2
public class TestThread02 implements Runnable{
//run方法线程体
public void run(){
for(int i=0;i<20;i++){
System.out.println("sxp01:"+i);
}
}
public static void main(String[] args) {
//主线程
//创建一个线程对象
TestThread02 testThread02=new TestThread02();
//创建线程对象,通过线程对象来开启我们的线程,代理
Thread thread=new Thread(testThread02);
thread.start();
for(int i=0;i<20;i++){
System.out.println("sxp02:"+i);
}
}
}
//输出:
sxp01:0
sxp02:0
sxp02:1
sxp02:2
sxp02:3
sxp01:1
sxp02:4
sxp02:5
sxp01:2
sxp01:3
sxp01:4
sxp01:5
sxp02:6
sxp01:6
sxp01:7
sxp01:8
sxp01:9
sxp02:7
sxp01:10
sxp01:11
sxp02:8
sxp02:9
sxp01:12
sxp01:13
sxp01:14
sxp01:15
sxp01:16
sxp01:17
sxp01:18
sxp01:19
sxp02:10
sxp02:11
sxp02:12
sxp02:13
sxp02:14
sxp02:15
sxp02:16
sxp02:17
sxp02:18
sxp02:19
多线程操作同一个对象(买票)
- 本次代码是有问题的 ,多个线程操作同一个资源,线程不安全,数据紊乱
//多个线程同时操作同一个对象
//多个线程操作同一个资源,线程不安全,数据紊乱
public class TestThread03 implements Runnable{
//票数
//被调整的资源
private int ticketNums=10;
@Override
public void run() {
while (true){
if (ticketNums<=0) {
break;
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"张票");
}
}
public static void main(String[] args) {
TestThread03 testThread03=new TestThread03();
//同一对象(都是testThread03),操控的ticketNums是同一个
new Thread(testThread03,"小明").start();
new Thread(testThread03,"老师").start();
new Thread(testThread03,"黄牛").start();
}
}
//输出:
黄牛拿到了第8张票
小明拿到了第9张票
老师拿到了第10张票
黄牛拿到了第6张票
老师拿到了第5张票
小明拿到了第7张票
小明拿到了第2张票
小明拿到了第1张票
老师拿到了第3张票
黄牛拿到了第4张票
模拟龟兔赛跑
//模拟龟兔赛跑
public class TestThread04 implements Runnable{
private static String winner;
@Override
public void run() {
for(int i=0;i<=100;i++){
//模拟兔子休息
if(Thread.currentThread().getName().equals("兔子") && i%10==0){
try {
Thread.sleep(3);
}catch (Exception e){
e.printStackTrace();
}
}
//判断比赛是否结束
boolean flag=gameOver(i);
if(flag){
break;
}
System.out.println(Thread.currentThread().getName()+"-->跑了"+i+"步");
}
}
//判断是否完成比赛
private boolean gameOver(int steps){
//判断是否有胜利者
if(winner!=null){//已经存在胜利者了
return true;
}else {
if (steps>=100){
winner=Thread.currentThread().getName();
System.out.println("胜利者是"+winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
TestThread04 testThread04=new TestThread04();
new Thread(testThread04,"兔子").start();
new Thread(testThread04,"乌龟").start();
}
}
方式3:Callable接口(了解)
- 实现Callable接口
- 需要返回值类型
- 重写call方法,需要抛出异常