线程 Thread
程序:保存在物理介质(磁盘、光盘、软盘)中的代码片段
进程:一旦程序运行起来 就变成操作系统当中的一个进程
进程 = 进行当中的程序
线程:程序当中一条独立的执行线索
为什么要使用多线程:
并不是单纯的为了效率 而是为了让程序
学会同时处理多个需求
让程序学会同一时间做多件事
宏观并行 而 微观串行
线程的五大状态(七大):
新生 就绪 运行 消亡
Born Runnable Running Dead
阻塞
Blocking
如何实现多线程的程序:
1.extends Thread
@Override
public void run(){
..;
}
2.implements Runnable
@Override
public void run(){
..;
}
3.implements Callable<T>
@Override
public T call()throws Exception{
..;
}
*: run()被定义为void 不能返回数据
*: run()没有任何throws
如何控制线程:
0.setPriority(int) : 设置线程优先级别
可选范围 1-10 默认为 5
*:优先级高的线程抢到时间片的概率高
1.static sleep(long) : 让当前线程休眠指定的毫秒数
2.static yield() : 让当前线程放弃已经持有的时间片 直接返回就绪
3.join() : 当前线程邀请另一个线程优先执行
在被邀请的线程执行结束之前 当前线程不再继续执行
*: 线程章节所有的静态方法 不要关注谁调用方法
而要关注调用出现在哪 出现在谁的线程体
就是操作哪个线程
*: 线程章节所有涉及主动进入阻塞的方法
都需要进行异常处理
线程类其它常用方法:
setName() + getName() : 设置和得到线程的名字
static activeCount() : 得到程序当中所有活跃线程的总数
活跃 = 就绪 + 运行 + 阻塞
static currentThread() : 得到正在运行的当前线程
setDaemon(true) : 设置线程成为守护线程
守护线程 = 守护线程是为其他线程提供服务的线程
当程序当中只有守护线程的时候 守护线程会自行结束
*: gc就是一个系统级别的守护线程
interrupt() : 中断打断线程的阻塞状态
线程类方法总结:
run()
start()
setPriority()
sleep()
yield()
join()
setName()
getName()
activeCount()
currentThread()
setDaemon()
interrupt()
多线程共享数据导致的并发错误:
根本原因:多线程共享同一个数据
直接原因:线程体当中连续的未必能够连续执行
导火索:时间片突然耗尽
多个线程共享同一个对象的时候 由于线程体当中连续的多行操作
未必能够连续执行 很可能操作了一部分之后
由于时间片突然耗尽 导致另一个线程抢到时间片
而直接取走了操作并不完整的数据 (错误的数据)
- 并发错误
多个线程共享的数据:临界资源
如何解决并发错误:
1st : synchronized 同步
Java当中每个对象都有一个锁标记
锁标记 = 锁旗标 = 互斥锁 = 互斥锁标记 = 监视器 = Monitor
a> 修饰代码块 :
synchronized(临界资源){
需要连续执行的操作1;
需要连续执行的操作2;
}
b> 修饰整个方法:
public synchronized void add(Object obj){...}
等价于从方法的第一行到方法的最后一行统统加锁
对调用方法的当前对象加锁
#: Vector Hashtable StringBuffer
它们之所以是线程安全的
就是因为底层大量的方法使用了synchronized
#: synchronized特性不会被子类方法继承 只能覆盖
2nd : java.util.concurrent.locks.ReentrantLock
java包的工具包的并发包的锁包的 可重入锁
lock() 上锁
unlock() 解锁
互斥锁标记使用过多 或者使用不当
就会造成多个线程相互持有对方想要申请的资源 不释放的情况下
又去申请对方已经持有的资源
从而双双进入对方已经持有资源的锁池当中
产生永久的阻塞
- 死锁 DeadLock
1> 中美科学家联合国饿死事件
2> 泉城路奔宝事件
3> AABB事件
```
如何解决死锁:
一块空间:对象的等待池
三个方法:
wait() : 让当前线程放弃已经持有的锁标记
并且进入调用方法的那个对象的等待池当中
notify() : 让当前线程从 调用方法的那个对象的
等待池当中随即唤醒一个线程
notifyAll() : 让当前线程从 调用方法的那个对象的
等待池当中唤醒全部线程
*:它们都是Object类的方法 并不是 Thread类的方法
*:想要调用这三个方法 必须先持有对象的锁标记
所以它们必然出现在synchronized当中
Java当中线程池的实现:
假如一个线程的完整执行时间为 T
则 T = t1 + t2 + t3
t1 : 创建一个线程所消耗的时间
t2 : 执行核心逻辑的时间
t3 : 销毁一个线程所消耗的时间
假如run()当中代码逻辑非常简单
则t2所占T的比例就会很小 此时喧宾夺主 主次不分
public class TestActiveCount{
public static void main(String[] args){
int lucky = (int)(Math.random()*10)+1;//1-10
for(int i = 0;i<lucky;i++){
EtoakThread et = new EtoakThread();
et.start();
}
while(true){
System.out.println(Thread.activeCount());
}
}
}
class EtoakThread extends Thread{
@Override
public void run(){
for(int i = 0;i<6666;i++){
System.out.println("ÕýÔÚÍê³É·þÎñ");
}
}
}
public class TestConcurrentError{
public static void main(String[] args){
Student stu = new Student("张曼玉","女士");
PrintThread pt = new PrintThread(stu);
ChangeThread ct = new ChangeThread(stu);
pt.start();
ct.start();
}
}
class Student{
String name;
String gender;
public Student(String name,String gender){
this.name = name;
this.gender = gender;
}
@Override
public String toString(){
return name + " : " + gender;
}
}
class PrintThread extends Thread{
Student stu;
public PrintThread(Student stu){
this.stu = stu;
}
@Override
public void run(){
while(true){
synchronized(stu){
System.out.println(stu);
}
}
}
}
class ChangeThread extends Thread{
Student stu;
public ChangeThread(Student stu){
this.stu = stu;
}
@Override
public void run(){
boolean isOkay = true;
while(true){
synchronized(stu){
if(isOkay){
stu.name = "梁朝伟";//梁朝伟 女士
stu.gender = "先生";//梁朝伟 先生
}else{
stu.name = "张曼玉";//张曼玉 先生
stu.gender = "女士";//张曼玉 女士
}
isOkay = !isOkay;
}
}
}
}
public class TestCurrentThread{
public static void main(String[] args){
EtoakThread et = new EtoakThread();
et.start();
et.setPriority(10);
Thread main = Thread.currentThread();
main.setPriority(10);
while(true){
System.out.println("我为人人");
}
}
}
class EtoakThread extends Thread{
@Override
public void run(){
while(true){
System.out.println("人人为我");
}
}
}
public class TestDeadLock{
public static void main(String[] args){
QCRoad r = new QCRoad();
QCRoad.Benz s900 = r.new Benz();
QCRoad.Bmw x9 = r.new Bmw();
s900.start();
x9.start();
}
}
class QCRoad{
Object east = new Object();
Object west = new Object();
class Benz extends Thread{
@Override
public void run(){
System.out.println("张总驾驶奔驰驶出家门去上学");
synchronized(east){
System.out.println("张总已经占领了泉城路东侧");
try{sleep(100);}catch(Exception e){e.printStackTrace();}
try{east.wait();}catch(Exception e){e.printStackTrace();}
synchronized(west){
System.out.println("张总又占领了泉城路西侧");
}
}
System.out.println("张总顺利的通过了泉城路");
}
}
class Bmw extends Thread{
@Override
public void run(){
System.out.println("王总驾驶宝马驶出家门去上学");
synchronized(west){
System.out.println("王总已经占领了泉城路西侧");
try{sleep(100);}catch(Exception e){e.printStackTrace();}
synchronized(east){
System.out.println("王总又占领了泉城路东侧");
east.notify();
}
}
System.out.println("王总顺利的通过了泉城路");
}
}
}
public class TestSetPriority{
public static void main(String[] args){
ThreadOne t1 = new ThreadOne();
t1.setPriority(1);
t1.start();
ThreadTwo t2 = new ThreadTwo();
t2.setPriority(10);
t2.start();
}
}
class ThreadOne extends Thread{//敬明
@Override
public void run(){
while(true){
System.out.println("小明去打篮球吗 不!我要写小说");//140cm
}
}
}
class ThreadTwo extends Thread{
@Override
public void run(){
while(true){
System.out.println("小明去图书馆看书吗 不!我要打篮球");//226cm
}
}
}