目录
1.概念:
- 程序:是指令和数据的集合,本身没有任何运行的含义,是一个静态的概念
- 进程:是程序的一次执行过程,它是一个动态的概念,是资源分配的单位
- 线程:通常在一个进程中包含若干个线程,一个进程中至少有一个线程,不然没有意义。先线程是CPU调度和执行的单位
2.线程状态:
3.线程方法:
方法 | 说明 |
setPriority(int newPriority) | 更改线程的优先级 |
static void sleep(long millis) | 在指定的毫秒数内让线程休眠 |
void join() | 等待该线程终止 |
static void yield() | 暂停当前正在执行的线程对象,并执行其他线程 |
void interrupt() | 中断线程(不建议使用) |
boolean isAlive() | 测试线程是否处于活动状态 |
4.实现:
4.1 继承Thread类
public class TestThread1 extends Thread {
@Override
public void run() {
// 重写run()方法,实现线程的执行操作
for (int i = 0; i <20; i++) {
System.out.println("我在看代码");
}
}
public static void main(String[] args) {
TestThread1 testThread1=new TestThread1();
// 创建线程对象
testThread1.start();
// 主线程
for (int i = 0; i < 20; i++) {
System.out.println("我在学习多线程");
}
}
}
运行结果:
总结:1.主线程和子线程同时执行
2.线程开启不一定立刻执行由cpu调度安排
4.2 实现Runnable接口
//实现Runnable接口
public class TestThread2 implements Runnable {
@Override
public void run() {
// 重写run()方法,实现线程的执行操作
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码");
}
}
public static void main(String[] args) {
TestThread1 testThread2 = new TestThread1();
//创建线程
new Thread(testThread2).start();
// 主线程
for (int i = 0; i < 20; i++) {
System.out.println("我在学习多线程");
}
}
}
总结:推荐使用实现Runnable接口,避免单继承局限性,灵活方便,方便同一个对象被多个线程使用。
5.线程方法示例
5.1 线程停止
建议线程正常停止,不建议死循环 建议使用标志位 不要使用stop或destroy
示例代码
public class TestStop implements Runnable {
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag) {
System.out.println("run ...Thread" + i++);
}
}
//停止线程
public void stop() {
this.flag = false;
}
public static void main(String[] args) {
TestStop testStop = new TestStop();
//创建线程
new Thread(testStop).start();
//循环1000次
for (int i = 0; i < 1000; i++) {
//当i等于900时,停止线程
if (i == 900) {
testStop.stop();
System.out.println("线程停止");
}
}
}
}
5.2 sleep方法
- 指定线程阻塞的毫秒数
- 存在异常InterruptedException
- 达到时间后进入就绪状态
- 模拟网络延时,倒计时等
- 每一个对象都有一把锁,sleep不会释放锁
示例代码
//模拟倒计时
public class testSleep {
public static void main(String[] args) {
try {
tenDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void tenDown() throws InterruptedException{
int num=10;
while(true){
Thread.sleep(1000);
System.out.println(num--);
if (num <= 0) {
break;
}
}
}
}
5.3 yield方法
- 礼让线程,让当前正在执行的线程暂停,但不阻塞
- 让线程从运行状态转为就绪状态
- 让CPU重新调度(不一定成功)
示例代码
public class TestYield {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield, "a").start();
new Thread(myYield, "b").start();
}
}
class MyYield implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "线程开始执行");
Thread.yield();
System.out.println(Thread.currentThread().getName() + "线程停止执行");
}
}
5.4 Join方法
Join合并线程。待此线程执行完成后,再执行其他线程,其他线程阻塞。(可以想象成插队)
示例代码
public class TestJoin implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("线程vip"+i);
}
}
public static void main(String[] args) throws InterruptedException {
TestJoin testJoin=new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
for (int i = 0; i < 500; i++) {
if(i==100){
thread.join();
}
System.out.println("main"+i);
}
}
}
6.线程安全问题
6.1 抢票
public class TestThread3 implements Runnable {
private int tickNum = 10;
@Override
public void run() {
//当tickNum小于等于0时,结束循环
while (true) {
if (tickNum <= 0) {
break;
}
try {
//线程休眠200毫秒
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
//输出当前线程名称和tickNum的值
System.out.println(Thread.currentThread().getName() + "--" + tickNum--);
}
}
public static void main(String[] args) {
//创建一个TestThread3类的实例
TestThread3 ticket = new TestThread3();
//创建线程,并传入参数ticket和"小明"
new Thread(ticket, "小明").start();
//创建线程,并传入参数ticket和"老师"
new Thread(ticket, "老师").start();
//创建线程,并传入参数ticket和"小红"
new Thread(ticket, "小红").start();
}
}
发现问题:多个线程操作统一资源,线程不安全,数据紊乱。
7.巩固练习:
7.1 龟兔赛跑
public class Race implements Runnable {
private String winner;
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
//判断当前线程是否为兔子,并且i是否为10的倍数
if (Thread.currentThread().getName().equals("兔子") && i % 10 == 0) {
try {
//线程休眠1毫秒
Thread.sleep(1);
} catch (InterruptedException 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;
}
//检查是否超过100步
{
if (steps >= 100) {
//设置获胜者为当前线程
winner = Thread.currentThread().getName();
System.out.println("winner is " + winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
// 创建一个Race对象
Race race = new Race();
// 创建一个新的线程,并将其命名为兔子
new Thread(race, "兔子").start();
// 创建一个新的线程,并将其命名为乌龟
new Thread(race, "乌龟").start();
}
}
8.Lambda表达式
- 避免匿名内部类过多
- 其实质属于函数式编程
函数式编程:
- 任何接口,如果只包含唯一一个抽象方法,他就是一个函数式接口
- 对于函数式接口可以使用Lambda表达式创建接口对象
8.1 lambda发展历程
public class TestLambda1 {
//3.静态内部类
static class Like2 implements ILike {
@Override
public void lambda() {
System.out.println("I like lambda2");
}
}
public static void main(String[] args) {
ILike like = new Like();
like.lambda();
like = new Like2();
like.lambda();
//4.局部内部类
class Like3 implements ILike {
@Override
public void lambda() {
System.out.println("I like lambda3");
}
}
like = new Like3();
like.lambda();
//5.匿名内部类
like = new ILike() {
@Override
public void lambda() {
System.out.println("I like lambda4");
}
};
like.lambda();
//6.用lambda简化
like = () -> {
System.out.println("I like lambda5");
};
like.lambda();
}
}
//1.定义一个函数式接口
interface ILike {
void lambda();
}
//2.实现类
class Like implements ILike {
@Override
public void lambda() {
System.out.println("I like lambda");
}
}