1.线程和进程
进程:进行中的程序,只有程序在运行过程中,才能称之为进程。计算机CPU分配资源的最小单位。
线程:每个进程至少包含一个线程,进程和线程的关系就像车和车轮,线程不是越多越好,要结合实际的硬件条件,线程是CPU调度和分派的基本单位
线程执行的基本概念:单核心CPU的情况线程是轮流交替执行,而且是随机的,每个线程最多执行的时间的20ms,间隔非常短,所以我们感知不到这个过程,宏观看上去就是“同时”执行
并行和并发:
并发:同时发生,比如你点了两份菜,从饭店老板的角度看,宏观的角度,你是同时吃完的,但是严格来说是轮流交替执行的,微观角度。
并行:同时执行,比如你和同桌一人点了一份菜,这才是真正意义的同时执行
2.创建线程的方式
1.继承Thread类,重写run方法
2.实现Runnable接口,实现run方法
> 面试题
调用start方法和run方法的区别?
调用start方法 会开启一个新的线程
不能调用run方法 因为不会开启新的线程
package com.qfedu.test1;
/**
* 创建线程方式1 继承Thread类 重写run方法
* 面试题:调用start方法和run方法的区别
* 启动线程调用start方法 会开启一个新的线程
* 不能调用run方法 因为不会开启新的线程
* @author WHD
*
*/
public class Test2 extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 线程执行run方法……");
}
public static void main(String[] args) {
Test2 t2 = new Test2();
t2.setName("线程A");
// t2.start(); // 启动线程 调用start方法 不能调用run方法
t2.run();
}
}
package com.qfedu.test1;
/**
* 创建线程方式2 实现Runnable接口 重写run方法
* @author WHD
*
*/
public class Test3 implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "在执行……");
}
public static void main(String[] args) {
Test3 t3 = new Test3();
Thread t1 = new Thread(t3);
// Thread t1 = new Thread(t3 , "线程A");
t1.start();
}
}
3.线程的状态
创建–》就绪–》运行–》阻塞–》死亡
package com.qfedu.test2;
/**
* 线程的状态
* 创建
* 就绪
* 运行
* 阻塞
* 死亡
* @author WHD
*
*/
public class Test4 extends Thread{
@Override
public void run() {
// 运行
// 阻塞 休眠 等待
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + "在执行" + i);
}
}
// 死亡
public static void main(String[] args) {
Test4 t1 = new Test4(); // 创建状态
Test4 t2 = new Test4(); // 创建状态
t1.start(); // 就绪状态
t2.start(); // 就绪状态
}
}
4.线程常用的方法
getName()获取线程名称
setName()设置线程名称
getPriority()获取线程优先级
setPriority()设置线程优先级
MAX_PRIORITY最大优先级 10
MIN_PRIORITY最小优先级1
NORM_PRIORITY默认优先级 5
sleep()休眠方法
join()线程插队
yield()线程礼让
interrupt()改变当前线程标识,标识此线程可以被中断,不是立即中断
isAlive()是否存活状态
stop()中断线程
currentThread()获取当前线程对象
5.同步关键字
synchronized:同步
适用场景:
修饰代码块:表示同步代码块
1.同时只能有一个线程访问此代码块
2.可以访问没有被修饰代码
3.其他被synchronized修饰的代码块同样被锁定
修饰方法:同步方法,同时只能有一个线程访问此方法。
package com.qfedu.test3;
/**
* 买票
* 多个人抢票
* 三个人 10张票
* synchronized 同步
* 适用场景:代码块 方法
*
* @author WHD
*
*/
public class BuyTicket2 implements Runnable{
private int count = 10;
@Override
public void run() {
while(true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this) {
if(count == 0) {
break;
}
count --;
System.out.println(Thread.currentThread().getName() + "抢到了第"+(10 - count)+"张票,还剩余" + count);
}
// 这里的 其他线程也访问
}
}
public static void main(String[] args) {
BuyTicket2 bt = new BuyTicket2();
Thread t1 = new Thread(bt, "赵四");
Thread t2 = new Thread(bt, "广坤");
Thread t3 = new Thread(bt, "大拿");
t1.start();
t2.start();
t3.start();
}
}
package com.qfedu.test3;
import java.util.Hashtable;
import java.util.Vector;
/**
* 买票
* 多个人抢票
* 三个人 10张票
* synchronized 同步
* 适用场景:
* 代码块 表示同时只能有一个线程执行当前代码块
* 方法 表示同时只能有一个线程执行当前方法
* 回顾我们之前所学线程安全的类 StringBuffer
*
* @author WHD
*
*/
public class BuyTicket3 implements Runnable{
private int count = 10;
@Override
public synchronized void run() {
while(true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(count == 0) {
break;
}
count --;
System.out.println(Thread.currentThread().getName() + "抢到了第"+(10 - count)+"张票,还剩余" + count);
}
}
public static void main(String[] args) {
BuyTicket3 bt = new BuyTicket3();
Thread t1 = new Thread(bt, "赵四");
Thread t2 = new Thread(bt, "广坤");
Thread t3 = new Thread(bt, "大拿");
t1.start();
t2.start();
t3.start();
}
}