一、多线程
多任务多条路径多个顺序同时执行就是多线程。
线程的优点和缺点
优点:
-
资源利用率更好
-
程序设计在某些情况下更简单
-
程序响应更快
-
提高效率,同时执行
缺点:
-
设计复杂
-
上下文切换开销大
1.线程的创建
1)继承Thread类,重写run()方法,run方法中定义多线程的线程体。
创建 Thread 子类的一个实例并重写 run 方法,run 方法会在调用 start()方法之后被执 行,示例如下:
package com.thread01;
//多线程:多任务多条路径多条顺序流同时执行
public class TextThread1 extends Thread{//继承Thread类
@Override
public void run() {//重写run方法
for(int i=0;i<100;i++) {
System.out.println("睡觉");
try {
//设置睡眠时间
Thread.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//创建多线程
TextThread1 t=new TextThread1();
//开始线程
t.start();
for(int i=0;i<100;i++) {
System.out.println("熬夜");
try {
//设置睡眠时间
Thread.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2)实现Runnable接口,重写run()方法
推荐使用的优点:1.避免单继承的局限性 2.实现资源共享。
package com.thread01;
/**
* 实现Runnable接口,重写run()方法
* 推荐:
* 1.避免单继承的局限性
* 2.实现资源共享
*
* */
public class TextThread2 implements Runnable{//实现Runnable接口
@Override
public void run() {//重写run方法
for(int i=0;i<20;i++) {
System.out.println("黑眼圈");
try {
//设置睡眠时间
Thread.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//创建多线程
Thread t=new Thread(new TextThread2());//因为实现接口通过子类实现
//开启线程
t.start();
for(int i=0;i<20;i++) {
System.out.println("贼精神");
try {
//设置睡眠时间
Thread.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3)实现Callable接口,重写call方法
2.线程的状态
1)五种状态
-
新生状态:new创建一个线程的时候
-
就绪状态:start(),线程会进入就绪队列,等待cpu的调度
-
运行状态:cpu调用分配时间片给线程,线程就会运行
-
阻塞状态:sleep(),一个线程一旦就如到阻塞状态,阻塞解除之后,不会马上恢复到运行,会恢复到就绪状态,再次等待cpu的调度
-
终止状态:线程结束了, 一个线程一旦进入终止状态,再也不会恢复
2)进入就绪状态的方式
-
start()
-
阻塞解除
-
线程切换,被切换的线程会恢复就绪状态
-
yield() :让出cpu的资源,恢复到就绪状态
3)进入阻塞状态的方式
-
sleep:线程睡眠
-
模拟网络延迟
-
放大问题的可能性
-
-
wait
-
join:插队线程,把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。
4)控制线程终止的方式
-
stop不推荐
-
正常执行结束
-
通过表示判断
5)线程优先级
优点:提高先执行的概率
-
getPriority() 返回该线程的优先级。
-
setPriority(int newPriority)改变这个线程的优先级。
-
优先级大小为1~10 ,1最小 , 10最大 , 默认是5。
3.线程安全
多线程同时操作同一份资源才有可能会出现线程不安全的问题,需要控制安全
1)同步锁: synchronized
2)同步方法
-
在方法上使用synchronized修饰
-
成员方法,相当于锁this,代码范围为方法
-
静态方法,相当于锁类(类的class对象),代码范围为方法
3)同步块
-
synchronized(锁的内容){同步的代码范围}
-
锁的内容: this 类.class 资源(成员变量)
-
类.class 相当于把这个类,类的所有内容锁住了,类的所有对象都锁住
package com.thred02; //多线程 /** * 简单模拟12306例子 * 100张票,想要让3个人同时买完这100张票 * 资源共享:共享资源100张票 * */ public class TextThread03 implements Runnable{ int num=100; public static void main(String[] args) { TextThread03 t=new TextThread03(); Thread t1=new Thread(t,"美人师兄"); Thread t2=new Thread(t,"东方不败"); Thread t3=new Thread(t,"齐天大圣"); t1.start(); t2.start(); t3.start(); } @Override public void run() { while(true) { synchronized (TextThread03.class) {//ThreadDemo02.class类的class对象() if(num<=0) { break; } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在购买第"+num--+"张票"); } } } }
-
this 当前调用成员方法的对象,相当于把这个对象的所有资源都锁住了,可以只锁资源
public class TextThread4 implements Runnable{ int num=100; public static void main(String[] args) { TextThread4 t=new TextThread4(); Thread t1=new Thread(t,"美人师兄"); Thread t2=new Thread(t,"东方不败"); Thread t3=new Thread(t,"齐天大圣"); t1.start(); t2.start(); t3.start(); } @Override public void run() { while(true) { if(!get()) { break; } } } public boolean get() { synchronized (this) {//this 当前调用成员方法的对象 if(num<=0) { return false; } try { Thread.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在购买第"+num--+"张票"); } return true; } }
-
资源: 成员变量,一定要是自定义的引用数据类型的对象
public class TextThread2 implements Runnable{ //int num=100; User u=new User(); public static void main(String[] args) { TextThread2 t=new TextThread2(); Thread t1=new Thread(t,"美人师兄"); Thread t2=new Thread(t,"东方不败"); Thread t3=new Thread(t,"齐天大圣"); t1.start(); t2.start(); t3.start(); } @Override public void run() { while(true) { synchronized (u) {//成员变量:自定义引用类型 if(u.n<=0) { break; } try { Thread.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在购买第"+u.n--+"张票"); } } } } //自定义引用类型 class User{ int n=100; }
-
-
锁的范围:{}->中代码的范围
4) 注意
-
锁的范围太大,效率低
-
锁的范围太小,锁不住
-
锁不变的内容