线程:
程序当中一条独立执行的线索
线程的五大状态:
新生 就绪 运行 消亡
Born Runnable Running Dead
阻塞
Blocking
实现线程的三种方式:
1.extends Thread
@Override
public void run(){...}
*:整车进口 直接start();
2.implements Runnable
@Override
public void run(){...}
*:进口发动机 配合自己造的国产外壳
3.金针菇...
/*
请实现三个线程
线程1 打印777次 我叫刘玄德 手持雌雄双股剑
线程2 打印666次 我叫关云长 手持青龙偃月刀
线程3 打印555次 我叫张翼德 手持AK47
*/
public class TestSetNameAndGetName{
public static void main(String[] args){
Student s1 = new Student("刘玄德",777,"雌雄双股剑");
Student s2 = new Student("关云长",666,"青龙偃月刀");
Student s3 = new Student("张翼德",555,"AK47");
s1.start();
s2.start();
s3.start();
}
}
/*
public class Thread{
private String name;
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}
*/
class Student extends Thread{
int age;
String blood;
public Student(String name,int age,String blood){
setName(name);//调用父类继承来的设置名字的方法
this.age = age;
this.blood = blood;
}
@Override
public void run(){
for(int i = 0;i<age;i++){
System.out.println("我叫"+getName()+" 手持"+blood);
}
}
}
如何控制线程:
0.setPriority(int) : 设置线程优先级别
1.static sleep(long) : 让当前线程休眠指定的毫秒数
2.static yield() : 让当前线程放弃时间片 直接返回就绪
3.join() : 让当前线程邀请调用方法的那个线程
优先执行 在被邀请的线程执行结束之前
当前线程不再执行 一直处于阻塞
*: 线程类所有静态方法 不要关注谁调用方法
而要关注 调用出现在谁的线程体 出现在哪就是操作谁
*: 线程类所有主动进入阻塞状态的方法
都必须进行异常处理...
public class TestJoin{
public static void main(String[] args)throws Exception{
MyThread mt = new MyThread();
mt.start();
//当前线程(主线程)邀请调用方法的线程(mt)优先执行
mt.join();
for(int i = 0;i<1000;i++){
System.out.println("梦回吹角连营");
}
}
}
class MyThread extends Thread{
@Override
public void run(){
for(int i = 0;i<1000;i++){
System.out.println("醉里挑灯看剑");
}
}
}
线程类其它常用方法:
setName() + getName() : 设置和得到线程的名字
static activeCount() : 得到程序当中所有活跃线程的总数
setDaemon(true) : 设置线程成为守护线程
*: 守护线程应当具有无限循环 防止其过早消亡
*: 设置线程成为守护线程的操作 必须早于它自己的start()
*: 守护线程应该具有最低的优先级 防止和核心业务争抢资源
interrupt() : 中断 打断线程的阻塞状态
public class TestActiveCount{
public static void main(String[] args){
int x = (int)(Math.random()*5)+5;//5-9
for(int i = 0;i<x;i++){
new MyThread().start();
}
while(true){
System.out.println(Thread.activeCount());
}
}
}
class MyThread extends Thread{
@Override
public void run(){
for(int i = 0;i<1000;i++){
System.out.println("洗刷刷 洗刷刷 哦哦~");
}
}
}
public class TestSetDaemon{
public static void main(String[] args){
GYJJ gy = new GYJJ();
//*:守护线程应该具有最低的优先级 防止其与核心业务争抢资源
gy.setPriority(1);
//*:它必须早于自身的start()
gy.setDaemon(true);
gy.start();
for(int i = 0;i<1000;i++){
System.out.println("西天取经上大路 一走就是几万里");
}
}
}
class GYJJ extends Thread{
@Override
public void run(){
//*: 守护线程通常都是无限循环 防止其过早消亡
while(true){
System.out.println("你这泼猴儿~");
}
}
}
public class TestInterrupt{
public static void main(String[] args){
MyThread mt = new MyThread();
mt.start();
//当前线程(主线程) 中断 调用方法的线程(mt) 的阻塞状态
mt.interrupt();
}
}
class MyThread extends Thread{
@Override
public void run(){
try{
Thread.sleep(999999999999999L);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("吖!神清气爽吖!");
}
}
*: 什么叫并发错误?
多个线程同时操作同一个数据(对象)
线程体(run())当中连续的多行语句
未必能够连续执行 很可能操作完成了一半的时候
时间片突然耗尽 而另一个线程直接抢走了
时间片 拿到了操作并不完整的错误数据
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 PrintThread extends Thread{
Student stu;
public PrintThread(Student stu){
this.stu = stu;
}
@Override
public void run(){
while(true){
synchronized(stu){
System.out.println(stu.name + " : " + stu.gender);
}
}
}
}
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;
}
}
}
}
class Student{
String name;
String gender;
public Student(String name,String gender){
this.name = name;
this.gender = gender;
}
}
*: 如何解决并发错误?
加锁
1st.语法级别的加锁
synchronized
同步关键字
2nd.面向对象思想的加锁
java.util.concurrent.locks.ReentrantLock
可重入锁
import java.util.concurrent.locks.*;
public class TestConcurrentErrorWithLock{
public static void main(String[] args){
Student stu = new Student("梁朝伟","先生");
Lock lock = new ReentrantLock();
PrintThread pt = new PrintThread(stu,lock);
ChangeThread ct = new ChangeThread(stu,lock);
pt.start();
ct.start();
}
}
class PrintThread extends Thread{
Student stu;
Lock lock;
public PrintThread(Student stu,Lock lock){
this.stu = stu;
this.lock = lock;
}
@Override
public void run(){
while(true){
//synchronized(stu){
lock.lock();
System.out.println(stu.name + " : " + stu.gender);
lock.unlock();
//}
}
}
}
class ChangeThread extends Thread{
Student stu;
Lock lock;
public ChangeThread(Student stu,Lock lock){
this.stu = stu;
this.lock = lock;
}
@Override
public void run(){
boolean isOkay = true;
while(true){
//synchronized(stu){
lock.lock();
if(isOkay){
stu.name = "张曼玉";
stu.gender = "女士";
}else{
stu.name = "梁朝伟";
stu.gender = "先生";
}
isOkay = !isOkay;
lock.unlock();
//}
}
}
}
class Student{
String name;
String gender;
public Student(String name,String gender){
this.name = name;
this.gender = gender;
}
}
*: synchronized关键字 能够修饰什么
修饰代码块
synchronized(临界资源){
需要连续执行的操作1;
需要连续执行的操作2;
.....
}
修饰整个方法
public synchronized void add(Object obj){
}
等价于从方法的第一行到方法最后一行统统加锁
对调用方法的当前对象加锁
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{
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("刘总和他的宝马已经占领泉城路西侧");
synchronized(east){
System.out.println("刘总和他的宝马又占领了泉城路东侧");
east.notify();//从east对象的等待池当中随机的唤醒一个线程
}
}
System.out.println("刘总顺利的通过了泉城路~");
}
}
}
*: 如何使用可重入锁
它 提供了两个核心方法:
lock() unlock()
*: unlock()最好出现在finally当中
以确保它一定会执行
*: 其构造方法 可以指定公平锁或非公平锁
*: 什么是公平锁?
多个线程对于锁资源的获取顺序 按照其申请的顺序
先来后到的得到资源 叫做:公平锁
而如果在释放锁的时候 所有线程竞争:非公平锁
*: 什么是死锁?
多个线程 相互持有对方想要获得的资源
不释放的情况下 又去申请对方已经持有到的资源
从而双双进入对方资源的锁池当中 产生永久的阻塞
*: 如何解决死锁?
一块空间:对象的等待池
三个方法:wait() / notify() / notifyAll()
*: 这三个方法并不是Thread类的方法
而是Object类的方法
由于Java世界中每个对象都有等待池
都可能去操作等待池 所以这三个方法必然
每个对象都会...
*: 这三个方法都只能在持有锁标记的前提下才能使用
否则不但调用失败 还会触发异常
*: 锁池和等待池的区别?
锁池 和 等待池 的区别~
锁池和等待池都是Java当中每个对象都有一份的存储空间
用于存放线程的
锁池:存放那些想要申请锁标记 但是暂时还没拿到锁标记的线程的
等待池:存放那些原本已经拿到锁标记
但是为了不跟别人形成相互制约 而主动放弃锁标记的线程的
进入的时候是否需要释放资源:
进入锁池 不需要释放资源
进入等待池 需要先释放资源
离开的时候是否需要调用方法:
离开锁池 不需要调用任何方法
离开等待池 必须由其它线程调用notify() / notifyAll()
离开之后去往什么状态:
离开锁池 直接返回就绪
离开等待池 直奔锁池
public class TestSwitchThread{
public static void main(String[] args){
RightThread rt = new RightThread();//
LeftThread lt = new LeftThread(rt);//
lt.start();//
}
}
class X{
static Object obj = new Object();
}
class LeftThread extends Thread{
Thread rt;
public LeftThread(Thread rt){
this.rt = rt;
}
@Override
public void run(){
synchronized(X.obj){
rt.start();
for(int i = 0;i<6666;i++){
System.out.println("左脚");//1
try{X.obj.wait();}catch(Exception e){e.printStackTrace();}//2
X.obj.notify();
}
}
}
}
class RightThread extends Thread{
@Override
public void run(){
synchronized(X.obj){
for(int i = 0;i<6666;i++){
System.out.println(" 右脚");//3
X.obj.notify();//4
try{X.obj.wait();}catch(Exception e){e.printStackTrace();}
}
}
}
}
*: 如何实现两个线程交替执行 (进一步思考 多个线程交替执行~)
顺丰快递 顺丰陆运
大货车 为了保证时效性 至少安排两个司机 倒班~
LeftThread RightThread
安师傅 刘师傅
1.先开4个小时
2.主动休息
3.开4个小时
4.唤醒安师傅
5.主动休息
6.唤醒刘师傅
已知:Vector类的add() 和 remove() 都是synchronized修饰的…
我们现在有一个Vector对象 名叫v
有两个线程对象 名叫 t1 和 t2
当t1线程调用v对象的add() 方法开始执行了
但是还没执行结束呢 时间片耗尽了
此时刚好t2线程抢到了时间片
问:
t2能不能调用v对象的add() ? 不能
t2能不能调用v对象的remove() ? 不能
已知:Vector类的add() 和 remove() 都是synchronized修饰的
我们现在有两个Vector对象 v1 和 v2
有两个线程对象 t1 和 t2
当t1线程调用v1对象的add() 方法开始执行了
但是还没执行结束呢 时间片耗尽了
t2线程抢到了时间片
问:
t2线程能不能调用v1对象的add()? 不能
t2线程能不能调用v1对象的remove()? 不能
t2线程能不能调用v2对象的add()? 能
t2线程能不能调用v2对象的remove()? 能
线程池~
线程池是一种标准的资源池模式
所谓资源池模式 就是在用户出现之前 就提前预留活跃资源
好让用户出现的第一时间 直接满足用户对资源的需求
将资源的创建和销毁操作都委托给资源池
从而提高用户感受
做饭 吃饭 刷碗
在路上 上课 在路上
import java.util.concurrent.*;//JUC包当中
public class TestThreadPool{
public static void main(String[] args)throws Exception{
//Executors.newSingleThreadExecutor();
//Executors.newCachedThreadPool();//缓存机制的线程池实现 1M=60S
ExecutorService es = Executors.newFixedThreadPool(2);//修复后可重用的线程池实现
ThreadOne t1 = new ThreadOne();
es.submit(t1);//把t1线程提交给执行器服务
ThreadTwo t2 = new ThreadTwo();
es.submit(t2);
ThreadThree t3 = new ThreadThree();
Future<String> f = es.submit(t3);
//System.out.println(f.get());//自我阻塞
es.shutdownNow();
//es.shutdown();
}
}
/*
Callable的出现的弥补了原本Runnable的两大不足
Runnable当中的run()
1.被定义为void方法 无法返回数据
2.run()没有任何throws声明 逼迫程序员 进行try catch处理
*/
class ThreadThree implements Callable<String>{
@Override
public String call()throws Exception{
for(int i = 0;i<10000;i++){
System.out.println("我是创建线程的第三种方式");
}
return "VIVA";
}
}
class ThreadTwo implements Runnable{
@Override
public void run(){
for(int i = 0;i<10000;i++){
System.out.println("我是创建线程的第二种方式");
}
}
}
class ThreadOne extends Thread{
@Override
public void run(){
for(int i = 0;i<10000;i++){
System.out.println("我是创建线程的第一种方式~");
}
}
}
假如一个线程的完整执行时间为 T
则 T 是由三部分时间足够的
T = t1 + t2 + t3
t1: 创建一个线程所消耗的时间
t2: 执行核心业务的时间 (run())
t3: 销毁一个线程所消耗的时间
如果run()当中操作非常简练 则t2所占T的比例就会很小
我们会觉得喧宾夺主 主次不分 付出和回报不成正比
shutdown()和shutdownNow()主要的区别
shutdown()和shutdownNow() 它们都能禁止新任务的提交
主要的区别在于
shutdownNow() 那些已经提交上去但是还在排队等待执行的线程
就无法执行了
常用的线程池种类:
newFixedThreadPool(int) : 修复后可重用的线程池
newCachedThreadPool() : 缓存机制的线程池
newSingleThreadExecutor() : 单一实例的线程执行器
*:阿里不允许自己的程序员直接使用官方提供的实现
要求程序员自己创建线程池执行器
那么你要了解ta的五个参数
1.线程池中预留的核心数量
2.最大线程数量
3.Keep Alive Time => 保持活跃的时间
4.Time Unit => 时间单位
5.一个队列集合 用于存放排队的线程任务~