一.线程
进程:程序在计算机上进行资源调度和分配的最小单元
线程:一个进程启动至少一条线程,该线程叫做主线程,线程是程序内部进行资源调度的最小单元
多线程:
一.线程三要素
CPU:那个程序抢到了CPU的执行权,哪个程序就开始执行
代码:线程执行体,主线程之外的线程需要做什么事情
数据:
宏观:程序中交互的所有变量
微观:变量中保存的数据
为什么学习多线程
1.解决一些耗时操作
2.解决一些业务逻辑的并发操作
二.Java中的多线程:
多线程是编码层面的多线程,比较简单
java.lang.Thread
java中开启一个线程就是创建了一个Thread对象
java程序中main方法就是主线程
创建多线程的两种方式
1.继承Thread类
实例变量是互不影响的
静态变量是可能会产生影响的
相关代码实现
package day18;
/**
* 继承Thread
* @author Acer
*
*/
public class FirstThread extends Thread{
private int i;
//重写run方法
@Override
public void run() {
//线程执行体
//一旦线程开始执行,则运行run方法里的内容
for(;i<100;i++) {
//输出一下i以及该线程的名字
System.out.println(this.getName()+" "+i);
try {
sleep(00);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//线程睡眠1秒中,相当于两条结果的中间间隔1秒
}
}
public static void main(String[] args) {
//让main线程也执行一下循环
for(int i=0;i<100;i++) {
Thread mt = Thread.currentThread();
System.out.println(mt.getName()+" "+i);
//当i等于20的时候,创建新的线程
if(i==20) {
Thread t1 = new FirstThread();//Thread-0
Thread t2 = new FirstThread();//Thread-1
// 启动线程,调用start方法
t1.start();
t2.start();
}
}
}
}
2.实现Runnable接口
因为Runnable接口的实现类没有start方法,所以还需要依赖Thread进行线程创建
总之一句话,java中只有Thread的实例代表一条线程
实例变量:
如果传入的是用一个Runnable的实现类实例,则会互相影响
如果传入的是两个不同的Runnable的实现类实例,则不会产生影响
静态变量:
package day18;
/**
* 实现Runnable接口
*
* @author Acer
*
*/
public class SecondThread implements Runnable {
private int i;
@Override
public void run() {
for (; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "id为" +Thread.currentThread().getId()+"优先级为"+Thread.currentThread().getPriority()+"数值为"+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
Thread mt = Thread.currentThread();
System.out.println(mt.getName() + "id为" + mt.getId() + "优先级为" + mt.getPriority() + "数值为" + i);
if (i == 10) {
SecondThread st1 = new SecondThread();
SecondThread st2 = new SecondThread();
// 因为st1和st2中没有start方法
// 所以实现了Runna接口的线程还需要依赖于Thread
Thread t1 = new Thread(st1,"线程一");
Thread t2 = new Thread(st2,"线程二");
t1.start();
t2.start();
}
}
}
}
线程的生命周期
1.新建状态(New)
创建Thread实例
Thread t = new Thread();
2.就绪状态(Runnable)
执行t.start
代表线程准备好开始CPU的抢夺
3.运行状态(Running)
执行run()方法里的代码块
4.阻塞状态(Blocked)
a.sleep
睡眠时间到了
被其他线程打断
有其他线程加入
则会退出阻塞状态转为就绪状态
b.join
当前线程阻塞,由调用join的线程先执行,
执行完毕之后当前线程进入就绪状态
5.死亡状态(Dead)
整个线程执行完毕,不能再开启该线程
会报异常,非法的线程状态
死亡状态的代码实现
package day18;
public class DeadThread extends Thread {
int i = 0;
@Override
public void run() {
for (; i < 100; i++)
//输出线程是否活着
System.out.println(getName() + " " + i+" "+isAlive());
}
public static void main(String[] args) {
DeadThread dt = new DeadThread();
System.out.println(dt.getState());
for(int i=0;i<100;i++) {
Thread mt = Thread.currentThread();
System.out.println(mt.getName() + " " + i+" "+mt.isAlive());
if(i==10) {
dt.start();
}
//当线程dt死亡后再开启一次
// if(i>10 || dt.isAlive() == false) {
// dt.start();
// }
if(i==60) {
dt.start();
System.out.println(dt.getState().toString());
}
System.out.println(dt.getState());
}
}
}
运行时会在i=60时报错,已经死亡的线程无法再次开启
初级龟兔赛跑:
乌龟和兔子的速度用随机数0-10
package day18;
/**
* 龟兔赛跑
*
* @author Acer
*
*/
public class RaceTest extends Thread {
private int sum = 0;
//可以给一个验证的旗标,
private static boolean isEnd = false;
public RaceTest(String name) {
super(name);
}
@Override
public void run() {
while(sum<100) {
if(isEnd == true) return;//stop();
//准备一个速度
int speed = (int)(Math.random()*11);
sum+=speed;
//先来给跑的线程准备一个睡眠
//
System.out.println(getName()+"跑了"+sum+"米");
//先来给跑的线程准备一个睡眠
try {
sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
isEnd = true;
System.out.println(getName()+"赢了!");
}
public static void main(String[] args) throws InterruptedException {
System.out.println("比赛开始");
//准备乌龟和兔子的线程
//作弊:兔子抢夺线程的机会大一点
RaceTest rabbit = new RaceTest("兔子");
RaceTest tortoise = new RaceTest("乌龟");
//在线程转入就绪状态前,设置优先级
rabbit.setPriority(Thread.MAX_PRIORITY);//作弊过程
tortoise.setPriority(Thread.MIN_PRIORITY);//作弊过程
//起跑
rabbit.start();
tortoise.start();
//join()代表该线程加入,线程等待调用join的线程结束之后进入就绪状态
rabbit.join();
tortoise.join();
System.out.println("比赛结束");
}
}
在代码中给兔子和乌龟分别设置max和min的优先级,可以使兔子比乌龟先到达100.但是可能是玄学吧,在测试的时候乌龟尽管是min的优先级,却还是常胜将军
线程安全
对于多个线程操纵的统一数据进行加锁,可以让某一线程在操作数据的时候,
别的线程如果也要访问该数据,将无法访问该数据,导致线程阻塞
二.心得
今天主要内容是线程,感觉也并没有想象中的那么难,就是在龟兔赛跑的时候明明给兔子设置了高优先级,乌龟仍然能把兔子按地上锤,可能这就是玄学吧.明天加油!