多线程

多线程:

多任务执行,如果没有多任务,就不需要多线程
线程和进程之间的区别:

1. 多线程的创建方式:

1.继承Thread,重写run()方法  + start()开启线程

public class ThreadDemo01 extends Thread{
	/*
	 * 多线程的线程体
	 */
	@Override
	public void run() {
		for(int i=0;i<=20;i++){
			try {
				Thread.sleep(1000);
			} 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();
		//th.run();  方法的调用,是单线程
		
		for(int i=0;i<=20;i++){
			//延时
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("一边陪女朋友...");
		}
		
	}
}

2.实现Runnable接口,重写run()方法
推荐使用: 1)避免单继承的局限性 2)实现资源共享

	public class ThreadDemo02 extends Object implements Runnable{
		public static void main(String[] args) {
			
			ThreadDemo02 demo=new ThreadDemo02();
			//创建线程
			Thread th=new Thread(demo);
			//开启线程
			th.start();
			
			for(int i=0;i<=100;i++){
				System.out.println("一边陪咳嗽...");
			}
			
		}
		/*
		 * 线程体
		 */
		@Override
		public void run() {
			for(int i=0;i<=100;i++){
				System.out.println("一边陪讲课...");
			}
		}
	}

静态的资源是属于类的,多个对象共享类的静态的内容,在静态区中
成员属于对象的.多个人对象,堆内存中就存在多个成员,互补影响
12306 买票的案例
需求: 100张票 3个人买完,只卖给这三个人,但是哪一个人买了哪一张票随便,卖完就结束

多任务同时执行,3个人同时买票,互相不影响,可以选择使用多线程
实现资源共享

public class Web12306_01 implements Runnable{
	//票  共享资源
	int tickets=100;
	
	public static void main(String[] args) {
		Web12306_01 web=new Web12306_01();
		Thread th1=new Thread(web,"张三");  //第二个参数为当前线程起名字
		Thread th2=new Thread(web,"李四");
		Thread th3=new Thread(web,"王五");
		
		th1.start();
		th2.start();
		th3.start();
		
	}

	@Override
	public void run() {
		//重复的买票
		while(true){
			
			System.out.println("-----------------");
			System.out.println("-----------------");
			System.out.println("-----------------");
			System.out.println("-----------------");
			System.out.println("-----------------");
			System.out.println("-----------------");
			//结束循环的条件 没票了就结束  tickets<=0
			// A   B
			if(tickets<=0){
				break;
			}
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			//买票的人:当前线程的名字  Thread.currentThread().getName()
			System.out.println(Thread.currentThread().getName()+"正在购买第"+tickets--+"票");
			//tickets--;
		}
	}
}

模拟龟兔赛跑:
规则:兔子每跑十步修饰10ms,乌龟不休息一直跑,100步就赢了,如果有人赢了,游戏就结束了
添加标识: String winner=null; 记录冠军的名字
winnner的值判断,游戏是否结束

	public class Racer02 implements Runnable{
		//记录冠军的名字,winnner的值判断,游戏是否结束
		String winner=null;	
		
		public static void main(String[] args) {
			Racer02 race=new Racer02();
			
			new Thread(race,"乌龟").start();
			new Thread(race,"兔子").start();
		}
	
		@Override
		public void run() {
			//i控制步数
			for(int i=1;i<=100;i++){
				if("兔子".equals(Thread.currentThread().getName()) && i%10==0){
					try {
						Thread.sleep(2);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				System.out.println(Thread.currentThread().getName()+"跑了"+i+"了...");
				//检测还跑不跑下一步了  true就是结束,false继续跑
				boolean flag=checkOver(i);
				if(flag){
					break;
				}
			}
		}
	
		/*
		 * 1.检测是否已经有人赢了
		 * 2.检测自己是不是赢了 
		 */
		private boolean checkOver(int i) {
			if(winner!=null){
				return true;
			}else{
				if(i==100){
					winner=Thread.currentThread().getName();
					return true;
				}
			}
			return false;
		}
	}

3.实现Callable接口,重写call()方法
优点: 可以返回值,可以抛出异常
缺点: 使用麻烦

	public class Racer03 implements Callable<Integer>{  //泛型Integer是call方法的返回值类型
		//记录冠军的名字,winnner的值判断,游戏是否结束
		String winner=null;	
		
		public static void main(String[] args) throws InterruptedException, ExecutionException {
			Racer03 race=new Racer03();
			
			//1.创建执行服务  创建一个线程池,用来管理线程的开启和结束
			ExecutorService server=Executors.newFixedThreadPool(2);
			//2.提交执行
			Future<Integer> result1=server.submit(race);
			Future<Integer> result2=server.submit(race);
			//3.获取返回值
			int steps1=result1.get();
			int steps2=result2.get();
			
			System.out.println(steps1+"-->"+steps2);
			
			//4.关闭服务
			server.shutdown();
		}
	
		/*
		 * 优点:
		 * 	可以有返回值
		 *	可以抛出异常
		 *
		 *  返回值:步数 一共跑了多少步
		 */
		@Override
		public Integer call() throws InterruptedException {
			//i控制步数
			for(int i=1;i<=100;i++){
				if("兔子".equals(Thread.currentThread().getName()) && i%10==0){
					Thread.sleep(2);
				}
				System.out.println(Thread.currentThread().getName()+"跑了"+i+"了...");
				//检测还跑不跑下一步了  true就是结束,false继续跑
				boolean flag=checkOver(i);
				if(flag){
					return i;
				}
			}
			return null;
		}
	
		/*
		 * 1.检测是否已经有人赢了
		 * 2.检测自己是不是赢了 
		 */
		private boolean checkOver(int i) {
			if(winner!=null){
				return true;
			}else{
				if(i==100){
					winner=Thread.currentThread().getName();
					return true;
				}
			}
			return false;
		}
	}

多线程可以写在不同的位置:

public class ThreadDemo04 {
	//静态内部类
	static class Inner implements Runnable{

		@Override
		public void run() {
			for(int i=1;i<=20;i++){
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println("一遍玩手机");
			}
		}
		
	}
	
	public static void main(String[] args) {
		//局部内部类
		class LocalInner implements Runnable{

			@Override
			public void run() {
				for(int i=1;i<=20;i++){
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println("一遍吃饭");
				}
			}
			
		} 
		
		new Thread(new Inner()).start();
		new Thread(new LocalInner()).start();
		//匿名内部类
		new Thread(new Runnable(){

			@Override
			public void run() {
				for(int i=1;i<=20;i++){
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println("一遍学习");
				}
			}
			
		}).start();
		//Lambda 表达式
		new Thread(()->{
				for(int i=1;i<=20;i++){
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println("一遍学习");
				}
			}).start();
	}
}

2. 线程状态 5个

  1. 新生状态: 创建线程 new Thread()
  2. 就绪状态: 调用start(),就绪队列 中的线程等待cpu的调度
  3. 运行状态: cpu把时间片分配给哪一个线程,这个线程才会运行
  4. 阻塞状态: sleep()…
  5. 终止状态: 结束,死亡

注意:
1.一个线程一旦进入终止状态,没有办法恢复,重新创建也是新的线程
2.一旦进入阻塞状态,不能直接恢复到运行状态的,恢复到就绪状态

一个线程如何进入到死亡状态?
1.正常执行完毕
2.调用destroy(),stop()
3.通过添加标识判断 —推荐

一个线程如何进入到就绪状态?
1.调用start()方法
2.阻塞解除
3.yield 礼让
4.线程切换

一个线程如何进入到阻塞状态:
1.sleep()
2.join()
3.wait()
4.io操作

sleep(毫秒数) 线程睡眠|休息
抱着资源睡觉,告诉cpu在多少时间中不要把资源分配给我这个线程,因为处于阻塞状态,到时间了就恢复到就绪状态,这个时候cpu才能把资源分配给我
sleep()的使用不要在任何同步环境下,但是如果在同步环境下使用了,在休眠途中,是不会释放对象锁的

模式网络延迟
放大问题的可能性

public class StateDemo01 implements Runnable{
	public static void main(String[] args) {
		//倒计时
		new Thread(new StateDemo01()).start();  //静态代理
		
		//Thread 代理类  StateDemo01真实角色
	}

	@Override
	public void run() {
		for(int i=10;i>=0;i--){
			if(i==0){
				System.out.println("结束啦,开始放假!!!!");
				return;
			}
			System.out.println(i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

yield 礼让线程 高风亮节
把cpu的资源让出,让cpu重新分配,但是有可能又选择了原线程,可以选择了其他线程,给了其他线程能够获取资源的机会

public class YieldDemo02 implements Runnable{
	public static void main(String[] args) {
		new Thread(new YieldDemo02(),"大王").start();
		new Thread(new YieldDemo02(),"小王").start();
	}

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + "---------start()");
		Thread.yield();  //礼让线程
		System.out.println(Thread.currentThread().getState());;
		System.out.println(Thread.currentThread().getName() + "---------end()");
	}
}

合并线程 ,插队线程
join() 处于阻塞状态的方法
join(ms) 等待指定毫秒数, 到点了,就阻塞等待了

	public class JoinDemo03 {
		public static void main(String[] args) {
			new Thread(new Father()).start();
		}
	}
	//爸爸类
	class Father implements Runnable{
	
		@Override
		public void run() {
			System.out.println("突然想抽烟了...");
			System.out.println("让儿子去买烟...");
			//儿子线程插队
			Thread th=new Thread(new Son());
			th.start();
			try {
				th.join();  //插队
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			//开启线程
			System.out.println("接过儿子买的烟,抽一口,人生都幸福了...");
			System.out.println("把零钱给儿子当跑腿费了...");
		}
		
	}
	
	//儿子类
	class Son implements Runnable{
	
		@Override
		public void run() {
			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("买完了,把烟给老爸..");
		}
	}

线程的优先级别: 1~10
默认一个线程的优先级: 5
MAX_PRIORITY 最大优先级 10
MIN_PRIORITY 最小优先级 1
NORM_PRIORITY 默认 5
setPriority() 设置线程优先级
getPriority() 获取线程优先级
优先级只能控制概率问题,不能角色到底谁先执行

获取线程状态
Thread.State getState() 返回该线程的状态。

	public class PriorityDemo04 {
		static class Inner implements Runnable{
	
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
			}
		}
		public static void main(String[] args) {
			/*Thread th1=new Thread(new Inner(),"A");
			Thread th2=new Thread(new Inner(),"B");
			Thread th3=new Thread(new Inner(),"C");
			
			th1.setPriority(Thread.MIN_PRIORITY);
			th2.setPriority(Thread.MAX_PRIORITY);
			th3.setPriority(Thread.NORM_PRIORITY);
			
			System.out.println(th1.getPriority());
			System.out.println(th2.getPriority());
			System.out.println(th3.getPriority());
			
			th1.start();
			th2.start();
			th3.start();*/
			//创建一个线程
			Thread th=new Thread(()->{
				for(int i=1;i<=10;i++){
					if(i==5){
						System.out.println(i);
						try {
							Thread.sleep(500);
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					System.out.println(i+"--->"+Thread.currentThread().getState());
				}
			},"陈相吉");
			//就绪
			System.out.println(th.getState());  //NEW
			
			th.start(); //就绪
			System.out.println(th.getState());  //RUNNABLE  运行和就绪都是这个状态
			
			while(true){
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(th.getState());  //TIMED_WAITING --sleep()
				//TERMINATED 终止
				
				if(Thread.State.TERMINATED==th.getState()){
					break;
				}
				
			}
			
		}
	}

3.synchronized关键字 同步锁

控制线程安全问题: ****
前提: 当多个线程同时操作同一份资源的时候,才有可能出现线程不安全问题
办法:使用同步锁 synchronized ,控制多线程执行时,某一段重要的代码,排队执行,其他代码可以同时执行,有能提高效率,有能控制安全

使用方式:

  1. 同步方法 : 在方法上使用synchronized关键字
    成员方法 : 对象,类,资源
    静态方法 : 静态的内容是属于类的,锁这个静态方法相当于锁类
    比较简单,但是范围太大,可能效率会低

  2. 同步块

     synchronized(this|类|资源){
     
    }
    

    this: 锁对象
    类名.calss: 只有一个,不变的对象内容,在类第一次加载金内存就存在了
    资源: 成员属性

    注意:
    同步一定要同步不变的内容(自定义类的对象地址),变的内容锁不住;
    锁的范围太大了,效率太低,锁的范围太小了,锁不住

    难点: 锁谁,this|资源|类|方法 锁的多大的范围

    public class SynchronizedDemo01 {
    	public static void main(String[] args) {
    		new Thread(()->{
    			System.out.println(SingleTon.newInstance());
    		}).start();
    		new Thread(()->{
    			System.out.println(SingleTon.newInstance());
    		}).start();
    	}
    	
    }
    
    //单例的类
    class SingleTon{
    	//私有的,静态的,该类的引用 ,存储唯一的对象
    	private static SingleTon single=null;
    	
    	//构造器私有化
    	private SingleTon(){}
    	
    	//公共的静态的访问方式
    	//同步方法
    	public static synchronized SingleTon newInstance(){
    		System.out.println("---------------------");
    		if(single==null){
    			single=new SingleTon();
    		}
    		return single;
    	}
    	
    	//同步块
    	public static SingleTon newInstance(){
    		System.out.println("---------------------");
    
    		synchronized (SingleTon.class) {
    		//synchronized (single) {  锁不住,会发生空指针,在第一次调用这个方法时候,single还指向null,没有执行一个对象
    			if(single==null){
    				single=new SingleTon();
    			}
    			return single;
    		}
    	}
    }
    

同步方法

public class Web12306_05 implements Runnable{
	//票  共享资源
	int tickets=100;
	
	public static void main(String[] args) {
		Web12306_05 web=new Web12306_05();
		Thread th1=new Thread(web,"张三");  //第二个参数为当前线程起名字
		Thread th2=new Thread(web,"李四");
		Thread th3=new Thread(web,"王五");
		
		th1.start();
		th2.start();
		th3.start();
	}
	@Override
	public void run() {
		//重复的买票
		while(true){
			//结束循环的条件 没票了就结束  tickets<=0
			//A B C
			boolean flag=buy();
			if(flag){
				break;
			}
		}
	}
	
	//没票的流程
	//同步成员方法
	public synchronized boolean buy(){
		System.out.println("----------------------------");
		if(tickets<=0){
			return true;
		}
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		//买票的人:当前线程的名字  Thread.currentThread().getName()
		System.out.println(Thread.currentThread().getName()+"正在购买第"+tickets--+"票");
		return false;
	}
}

同步块 类.calss

锁类,相当于把这个类的所有对象,内容都锁住了,如果有些对象不需要锁,我们就只锁某一个对象

public class Web12306_06 implements Runnable{
	//票  共享资源
	int tickets=100;
	
	public static void main(String[] args) {
		Web12306_06 web=new Web12306_06();
		Thread th1=new Thread(web,"张三");  //第二个参数为当前线程起名字
		Thread th2=new Thread(web,"李四");
		Thread th3=new Thread(web,"王五");
		
		th1.start();
		th2.start();
		th3.start();	
	}
	@Override
	public void run() {
		//重复的买票
		while(true){
			//结束循环的条件 没票了就结束  tickets<=0
			//A B C
			synchronized (Web12306_06.class) {  //独一份的,锁之前就存在的,不变的
				if(tickets<=0){
					break;
				}
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//买票的人:当前线程的名字  Thread.currentThread().getName()
				System.out.println(Thread.currentThread().getName()+"正在购买第"+tickets--+"票");
			}
		}
	}
}

同步块 对象 this

锁对象,把这个对象所有的资源全部锁住了,如果指向锁住其中的某一个资源,建议可以锁资源

	public class Web12306_07 implements Runnable{
		//票  共享资源
		int tickets=100;
		
		public static void main(String[] args) {
			Web12306_07 web=new Web12306_07();
			Thread th1=new Thread(web,"张三");  //第二个参数为当前线程起名字
			Thread th2=new Thread(web,"李四");
			Thread th3=new Thread(web,"王五");
			
			th1.start();
			th2.start();
			th3.start();
		}
		@Override
		public void run() {
			//重复的买票
			while(true){
				//结束循环的条件 没票了就结束  tickets<=0
				//A B C
				synchronized (this) {  //当前调用这个成员方法的对象
					if(tickets<=0){
						break;
					}
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					//买票的人:当前线程的名字  Thread.currentThread().getName()
					System.out.println(Thread.currentThread().getName()+"正在购买第"+tickets--+"票");
				}
			}
		}
	}

同步块 资源 (成员变量)

自定义引用数据类型的对象永远不变

	public class Web12306_08 implements Runnable{
		//票  共享资源  tickets就指向这个对象,不会改变
		Ticket tickets=new Ticket();
		
		public static void main(String[] args) {
			Web12306_08 web=new Web12306_08();
			Thread th1=new Thread(web,"张三");  //第二个参数为当前线程起名字
			Thread th2=new Thread(web,"李四");
			Thread th3=new Thread(web,"王五");
			
			th1.start();
			th2.start();
			th3.start();
		}
		@Override
		public void run() {
			//重复的买票
			while(true){
				//结束循环的条件 没票了就结束  tickets<=0
				//A B C
				synchronized (tickets) {  //tickets 变量,数值
					if(tickets.nums<=0){
						break;
					}
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					//买票的人:当前线程的名字  Thread.currentThread().getName()
					System.out.println(Thread.currentThread().getName()+"正在购买第"+tickets.nums--+"票");
				}
			}
		}
	}
	
	//自定义的引用数据类型
	class Ticket{
		int nums=100;
	}

线程通信

wait() 等待 notify()唤醒
wait() 进入到对象的等待池中进行等待,等待对方线程的唤醒,告诉cpu在等待时刻不要为线程分配资源,并且会释放对象的锁
线程进入到等待状态–>等待阻塞
sleep() 不会释放对象锁
notify() 唤醒对象等待池中的某一个线程,唤醒不代表就可以执行,必须还要获取到对象锁才可以,cpu调度才可以执行
notifyAll() 唤醒全部
要求使用在共同的对象锁的环境下,锁方法,锁块…

通过信号灯法实现生产者消费者模式
街道案例:
人走 南北 绿灯true
车走东西 红灯 false
公用街道对象 存储在信号灯

	public class Demo01 extends Object{
		public static void main(String[] args) {
			Street street = new Street();
			new Thread(new Person(street)).start();
			new Thread(new Car(street)).start();
		}
	}
	
	//街道
	class Street{
		//红绿灯 信号灯
		boolean flag=true;
		
		//南北  绿灯 true
		public synchronized void ns(){
			if(!flag){
				try {
					wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("人走.....");
			this.notify();  //唤醒
			flag=false;
			
		}
		//东西  红灯false
		public synchronized void we(){
			if(flag){
				try {
					wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}else{
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("车走...");
				notifyAll();
				flag=true;
			}
		}
	}
	
	//人
	class Person implements Runnable{
		//公用的街道
		Street street;
		
		public Person(Street street) {
			super();
			this.street = street;
		}
	
		@Override
		public void run() {
			while(true){
				street.ns();//人走南北
			}
		}
	}
	//车
	class Car implements Runnable{
		//公用的街道
		Street street;
		
		public Car(Street street) {
			this.street = street;
		}
	
		@Override
		public void run() {
			while(true){
				street.we();  //车走东西
			}
		}
	}

注意:
死锁:容易造成死锁

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值