多线程

多线程

概念

  • 进程与线程的区别:

    区别进程线程
    根本区别作为资源分配的单位调度和执行的单位
    开销每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器,线程切换开销较小
    所处环境在操作系统中可以同时运行多个程序在同个程序中可以同时执行多个顺序流
    分配内存系统在运行时回为每个进程分配不同的内存空间除CPU外,不会为线程分配内存,线程组只能共享资源
    包含关系没有线程的进程可以看做是单线程的线程是进程的一部分
  • 线程的优缺点:

    • 优点:资源利用率高;程序设计在某些情况下更简单;程序响应更快
    • 缺点:一般情况下多线程程序设计更复杂;上下文切换的的开销

创建线程的三种方式:

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

  2. 实现 Runnable 接口,重写 run() 方法 + new Thread(Runnable target).strat() 方法开启线程

    • 优点:1)避免单继承的局限性; 2)实现资源共享
  3. 实现 Callable 接口,重写 call() 方法

    • 优点:1)可以有返回值; 2)可以抛出异常

    • 缺点:使用复杂

      //1.创建执行服务  创建一个线程池,用来管理线程的开启和结束
      ExecutorService server = Executors.newFixedThreadPool(1);
      //2.提交执行
      Future<E> result = server.submit(Callable target);
      //3.获取返回值
      Object obj = result.get();
      
  4. 内部类与多线程:

    public class ThreadDemo {
    	//静态内部类
    	static class Inner implements Runnable {
    		@Override
    		public void run() {
    			for (int i = 1; i <= 20; i++) {
    				try {
    					Thread.sleep(100);
    				} catch (InterruptedException e) {
    					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) {
    						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) {
    						e.printStackTrace();
    					}
    					System.out.println("一遍学习");
    				}
    			}		
    		}).start();
    		//Lambda 表达式
    		new Thread(() -> {
    				for (int i = 1; i <= 20; i++) {
    					try {
    						Thread.sleep(100);
    					} catch (InterruptedException e) {
    
    						e.printStackTrace();
    					}
    					System.out.println("一遍学习");
    				}
    			}).start();
    	}
    }
    

用户线程与守护线程:

  • 线程:用户线程User;守护线程 Deamon
  • 如果程序中没有用户线程的存在了,所有的守护线程自动结束,只要还有一个用户线程,就不会强制结束守护线程
  • 默认所有的线程为用户线程
  • 经典的守护线程案例,垃圾回收机制
  • 设置守护线程: thread.setDaemon(true);
    • 要求: 在线程开启start()方法之前使用

线程的五种状态:

  1. 新生状态:创建线程 new Thread();
  2. 就绪状态:就绪队列中的线程,等待cpu的调度:调用start(); | yield(); | 线程切换 | 阻塞解除
  3. 运行状态:cpu把时间片分配给哪一个线程,这个线程才会运行
  4. 阻塞状态:sleep(); | join(); | wait(); | IO操作(Scanner); … …
  5. 结束状态:结束,死亡:正常执行完毕 | 调用destroy();stop(); | 通过添加标识判断
  • sleep():注意不要在任何同步环境下使用,如果在同步环境下使用了,在休眠途中,是不会释放对象锁的
  • yield():把cpu的资源让出,让cpu重新分配,给了其他线程能够获取资源的机会
  • join():合并线程 ,插队线程;join(ms):等待指定毫秒数, 到点了,就阻塞等待了
  • 线程的优先级:
    • 1~10 ,默认一个线程的优先级: 5
    • MAX_PRIORITY 最大优先级:10
    • MIN_PRIORITY 最小优先级:1
    • NORM_PRIORITY 默认:5
    • setPriority():设置线程优先级
    • getPriority():获取线程优先级
    • 优先级只能控制概率问题,不能角色到底谁先执行
  • 获取线程状态:
    • Thread.State getState():返回该线程的状态(枚举类型)
    • NEW:新生状态
    • RUNNABLE:运行和就绪都是这个状态
    • TIMED_WAITING:阻塞状态
    • TERMINATED:终止

线程同步:

​ 控制线程安全问题

  • 前提:当多个线程同时操作同一份资源的时候,才有可能出现线程不安全问题
  • 办法:使用同步锁 --> synchronized
  • 使用方法:
    • 同步方法:在方法上使用synchronized关键字(较简单,但是范围太大,效率低)
      • 成员方法
      • 静态方法
    • 同步块:synchronized(this|类|资源){ }
      • this: 锁对象
      • 类名.calss:只有一个,不变的对象内容,在类第一次加载进内存就存在了
      • 资源: 成员属性
    • 注意:
      • 锁谁:this|资源|类|方法?同步一定要锁同步不变的内容(自定义类的对象地址),变的内容锁不住
      • 锁的多大的范围:的范围太大了,效率太低,锁的范围太小了,锁不住
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值