线程的创建
线程和进程之间的区别:
进程:每一进程都有自己独立的代码和数据空间,进程之间切换开销较大,一个进程包含1~n个线程,进程是资源分配的最小单位
线程:同一类的线程共享代码和数据空间 ,线程之间切换开销较小,线程是cpu调度的最小单位
阶段
线程和进程一样都分五个阶段:创建 就绪 运行 堵塞 终止
区分
多进程:操作系统能同时运行多个任务(程序)
多线程:同一个程序中多个顺序流执行 (多任务执行就是多线程)
单线程:单任务 单个路径执行 需要排序 效率较低
学习多线程的掌握核心
线程的开启方式 线程的状态 线程安全
线程的创建方式:
1.继承Thread类,重写run() start()
2.实现Runnable接口,重写run() --推荐
3.实现Callable接口,重写call()
线程创建的第一种方式(继承Thread类,重写run() 方法, start())
public class ThreadDemo01 extends Thread{
public void run(){
for(int i = 1;i<=20;i++) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("一边敲代码,一边吃东西");
}
}
//主线程
public static void main(String[] args) {
//创建一个线程
ThreadDemo01 th = new ThreadDemo01();
//开启
th.start(); //等待cpu的调度,时间片同一时刻分配给哪个线程,哪一个线程就会执行
for(int i = 1;i<=20;i++) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("一边敲代码");
}
}
}
线程创建的第二种方式(实现Runnable接口,重写run() --推荐)
public class ThreadDemo02 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 1;i<=20;i++) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("一边洗澡");
}
}
public static void main(String[] args) {
//1.创建线程
Thread th = new Thread(new ThreadDemo02());
//2.开启线程
th.start();
for(int i = 1;i<=20;i++) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("一边唱歌");
}
}
}
优点:避免单继承的局限性
实现资源共享
案例:Web12306共享资源
实现Runnable接口,实现资源共享案例(当一份资源多个代理同时操作这就是并发,需要控制安全)
案例:有100张票,3个人分别把这100张票买完
public class Web12306_03 implements Runnable{
//共享资源 100张票
int tickets = 100;
public static void main(String[] args) {
Web12306_03 web = new Web12306_03();
//创建线程
Thread th1= new Thread(web,"张3");
Thread th2= new Thread(web,"lisi");
Thread th3= new Thread(web,"wangwu");
//开启线程
th1.start();
th2.start();
th3.start();
}
@Override
public void run() {
// A B C
while(true) {
if(tickets<=0) {
break;
}
//A B C
try {
Thread.sleep(100); //ms数
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在购买第"+tickets--);
}
}
}
线程的开启
public class ThreadDemo06 {
//静态内部类
static class Inner01 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i<=10;i++) {
System.out.println("一边敲代码");
}
}
public static void main(String[] args) {
//局部内部类
class Inner02 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i<=10;i++) {
System.out.println("一边嚼口香糖");
}
}
}
new Thread(new Inner01()).start();
new Thread(new Inner02()).start();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i<=10;i++) {
System.out.println("一边吃苹果");
}
}
线程状态
新生:new 一个线程一旦进入新生状态就会有自己的内存和工作空间
- 就绪:start()方法,线程进入就绪状态,进去就绪不代表会马上执行,会进入就绪队列,等待cpu调度
- 运行:当系统选中某一个正在等待线程,一旦得到获取cpu调度资源,才会运行
- 阻塞:sleep。。。
- 死亡|终止 :线程结束
- 注意:如果一个线程一旦进入死亡状态,不会恢复,重新创建是一个新的线程了
如果一个线程一旦进入阻塞状态,不会马上恢复运行状态,会先进入就绪,等待cpu的调度 - 一个线程如何进入终止状态:
- 1.正常执行完毕
- 2.stop方法,destory(废弃)
- 3.添加外部标识 控制
- 如何进入就绪状态:
- 1.start()
- 2.阻塞解除
- 3.调用yield
- 4.线程切换
- 如何让进入阻塞状态
- 1.sleep
- 2.wait
- 3.join
- sleep:线程进入睡眠状态,参数为ms数
- 1.放大问题的可能性
- 2.模拟网络延迟
- 模拟网络延迟倒计时:倒计时10.。9.。8.。。7。。。。结束
Yield礼让线程(当线程执行到yield,会让出cpu的资源,直接进入就绪状态)
public class YieldDemo02 implements Runnable{
public static void main(String[] args) {
YieldDemo02 y = new YieldDemo02();
new Thread(y,"A").start();
new Thread(y,"B").start();
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+"开始了");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"结束了");
}
}
Join插队线程
public class JoinDemo03 {
public static void main(String[] args) {
new Thread(new Father()).start();
}
}
class Father implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("想吸烟了");
System.out.println("让儿子去买烟");
//开启线程
Thread th = new Thread(new Son());
th.start();
try {
th.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("儿子丢了,去找儿子");
}
System.out.println("接过烟,吸一口");
}
}
class Son implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("接过钱,去买烟");
System.out.println("看见游戏厅,进去玩10s");
for(int i =1;i<=10;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(i+"s");
}
System.out.println("赶紧去买烟");
System.out.println("买好了");
}
}
线程优先级
获取线程状态
public class ThreadStateDemo04 {
public static void main(String[] args) {
Thread th = new Thread(()->{
for(int i =1;i<=10;i++) {
if(i==5) {
System.out.println("线程即将休眠");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(i);
}
});
System.out.println("th线程状态"+th.getState());
th.start();
System.out.println("th线程状态"+th.getState());
while(th.getState()!=Thread.State.TERMINATED) {
System.out.println("th线程状态"+th.getState());
}
System.out.println("th线程状态"+th.getState());
}
}
线程优先级
线程优先级:1~10 默认5
- void setPriority(int newPriority)
-
更改线程的优先级
- int getPriority()
- 返回线程的优先级
- MAX_PRIORITY MIN_PRIORITY
注意:设置优先级,可以提高优先执行的可能,但不一定先执行
public class PriorityDemo05 implements Runnable{
public static void main(String[] args) {
PriorityDemo05 p = new PriorityDemo05();
Thread th1 = new Thread(p,"zhangsan");
Thread th2 = new Thread(p,"lisi");
Thread th3 = new Thread(p,"wangwu");
Thread th4 = new Thread(p,"zhaoliu");
th1.setPriority(1);
th2.setPriority(Thread.MAX_PRIORITY);
th3.setPriority(Thread.MIN_PRIORITY);
th4.setPriority(10);
th1.start();
th2.start();
th3.start();
th4.start();
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getPriority()+Thread.currentThread().getName());
}
}