zoukankan      html  css  js  c++  java
  • java线程基础梳理

    java线程

    概述
    • 进程:运行时概念,运行的应用程序,进程间不能共享内存
    • 线程:应用程序内并发执行的代码段,可以共享堆内存和方法区内存,而栈内存是独立的。
    • 并发理解:在单核机器上,从微观角度来看,一段时间内cup只能执行一个任务,但是因为cup在只执行一段代码段的时候大部分的时间是处于等待程序的,所以可以再开几条程序,然后通过轮询机制,让cpu执行多个进程,从宏观角度来看就是所谓的并发。如果机器是多核,那么就是真正的并发。
    线程调度模型
    • 线程的调度模型分为: 分时调度模型和抢占式调度模型,Java使用抢占式调度模型
      • 分时调度模型: 所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
      • 抢占式调度模型: 优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些.
    • 线 程 优 先 级 主 要 分 三 种 : MAX_PRIORITY( 最 高 级 );MIN_PRIORITY ( 最 低 级 )NORM_PRIORITY(标准)默认
    java 程序的运行原理?
    • java 命令会启动 java 虚拟机,启动 JVM,等于启动了一个应用程序,表示启动了一个进程。该进程会自动启动一个“主线程”,然后主线程去调用某个类的 main 方法。所以 main方法运行在主线程中。在此之前的所有程序都是单线程的。
    • 一个栈就是一个线程,所谓的并发就是多个不同的栈。
    线程创建
    • 继承Thread
      • 线程编写要继承 java.lang.Thread
      • 重写run方法
      • 调用的时候调用线程类的start()方法,run方法是让cpu调用的。所以start()方法调用后run方法不会立刻调用。
    • 实现runable接口
    class CreateRunnable implements Runnable {
    	@Override
    	publicvoid run() {
    		for (inti = 0; i< 10; i++) {
    			System.out.println("i:" + i);
    		}
    	}
    
    }
    public class ThreadDemo2 {
    	publicstaticvoid main(String[] args) {
    		System.out.println("-----多线程创建开始-----");
    		// 1.创建一个线程
    		CreateRunnable createThread = new CreateRunnable();
    		// 2.开始执行线程 注意 开启线程不是调用run方法,而是start方法
    		System.out.println("-----多线程创建启动-----");
    		Thread thread = new Thread(createThread);
    		thread.start();
    
    	}
    }
    
    • 使用匿名内部调用
    System.out.println("-----多线程创建开始-----");
    		 Thread thread = new Thread(new Runnable() {
    			public void run() {
    				for (int i = 0; i< 10; i++) {
    					System.out.println("i:" + i);
    				}
    			}
    		});
    		 thread.start();
    		 System.out.println("-----多线程创建结束-----");
    
    线程分类
    • 主线程、子线程、GC线程
      • 一个进程中肯定要有主线程。一般是用main函数来创建
      • java主线程结束是不影响子线程的。
      • GC线程是守护线程。
      • 守护线程随着主线程的销毁而销毁。
      • 在一个线程start前用thread.setDaemon(true)可以将用户线程变成守护线程。
    • 守护线程和用户线程
      • 从线程分类上可以分为:用户线程(以上讲的都是用户线程),另一个是守护线程。
      • 其它所有的用户线程结束,则守护线程退出!因为 daemon守护线程是守护非守护线程的
      • setDaemon(true) 使线程变成守护线程
      • 守护线程一般都是无限执行的.
      • 例如 java 中著名的垃圾回收器GC线程就是一个守护线程。
    线程安全和锁
    • 任何对象都可以是锁,因为锁的本质是参照物,类似于红绿灯,上课铃等等,关键是大家要看一个参照物。
    • 同步代码块(以object为锁)
    		synchronized(object){
    			[并发逻辑]
    		}
    
    • 加锁里的逻辑要尽量少
    • 同步方法
    	public synchronized int getTicket(){
    		
    	}
    
    • 同步方法(非静态)是以当前对象作为锁。
      • 如果用非静态同步方法加锁,一般独立出一个对象池,将同步方法放在对象池内,然后多线程对象每次从同一个对象池取资源。
    • 同步方法(静态) 是以类作为锁。
    线程生命周期

    enter image description here
    enter image description here

    • enter image description here
    • yield();方法可以让线程方法暂时放弃cpu的抢占,但是一旦放弃后又马上开始抢,有谦让的意义
    • Thread.sleep(time) 静态方法 让当前线程休眠time毫秒,不去抢占cpu
    • join等到指定的线程执行完后执行
    sleep() 与 wait()的比较
    • 相同点:wait()的作用是让当前线程由“运行状态”进入“等待(阻塞)状态”的同时,也会释放同步锁。而sleep()的作用是也是让当前线程由“运行状态”进入到“休眠(阻塞)状态”
    • 不同点:wait()会释放对象的同步锁,而sleep()则不会释放锁
    join()方法作用
    • 当在主线程当中执行到t1.join()方法时,就认为主线程应该把执行权让给t1
    线程死亡
    • 有两个原因会导致线程死亡:
      - 1) run方法正常退出而自然死亡,
      - 2) 一个未捕获的异常终止了run方法而使线程猝死。
      - 为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是可运行或被阻塞,这个方法返回true; 如果线程仍旧是new状态且不是可运行的, 或者线程死亡了,则返回false.
    阻塞状态
    • 线程运行过程中,可能由于各种原因进入阻塞状态:
      • 1>线程通过调用sleep方法进入睡眠状态;
      • 2>线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
      • 3>线程试图得到一个锁,而该锁正被其他线程持有;
      • 4>线程在等待某个触发条件;
    参考
  • 相关阅读:
    Luogu P2181 对角线 简单数学,细节
    vscode 配置C、C++环境,编写运行C、C++(转)
    用家庭电脑架设minecraft服务器
    用阿里云架设我的世界(minecraft)服务器
    在线数独
    数学物理笔记
    复活的asdf1229
    test
    GitHub从小白到精通(第一章 初识)
    抛砖引玉,浅讲Handler和线程的关系
  • 原文地址:https://www.cnblogs.com/frankltf/p/10311848.html
Copyright © 2011-2022 走看看