线程

线程:

程序当中一条独立执行的线索

线程的五大状态:

新生		就绪		运行		消亡
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.一个队列集合 用于存放排队的线程任务~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值