多线程基础整理

1.进程 与 线程

进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间

线程:是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行. 一个进程最少有一个线程

线程实际上是在进程基础之上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分
成若干个线程

2.线程调度

分时调度
所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。

抢占式调度
优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。

CPU使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核新而言,某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是 在同一时刻运行。 其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的 使用率更高。

3.并发与并行

并发:指两个或多个事件在同一个时间段内发生。

并行:指两个或多个事件在同一时刻发生(同时发生)。

4.多线程类Thread的常用方法

Thread常用的构造方法

Thread() 												分配新的 Thread对象。  
Thread?(Runnable target) 								分配新的 Thread对象。  
Thread?(Runnable target, String name) 					分配新的 Thread对象。  

普通的方法以及静态的方法,想要结束线程,不能使用stop(),可能是导致正在执行的线程来不及释放内存,可以设置标志位,来判断是否放要结束

long 	getId() 								返回此Thread的标识符。  
String 	getName() 								返回此线程的名称。 
int 	getPriority() 							返回此线程的优先级。 
void 	setPriority?(int newPriority) 			更改此线程的优先级。 
void 	start() 								导致此线程开始执行; Java虚拟机调用此线程的run方法。 
static 	void sleep?(long millis) 				导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,具体取决于系统计时器和调度程序的精度和准确性。  
static 	void sleep?(long millis, int nanos) 	导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数加上指定的纳秒数,具体取决于系统定时器和调度程序的精度和准确性。 
void 	setDaemon?(boolean on) 					将此线程标记为 daemon线程或用户线程 

5.实现Runnable 与 继承Thread 相比的优势

 /**
 * 1.   通过创建任务,然后给线程分配任务的方式来实现多线程,更适合多个线程同时执行相同任务的情况
 * 2.   可以避免单继承带来的局限性
 * 3.   任务与线程本身时分离的,提高了程序的壮性
 * 4.   后续学习的线程池技术,只接受runnalble类型的任务,而不接受Thread类型的线程
 *
 * 5.   Thread也有用处,当使用匿名内部类方法,即只调用一次时,很方便
     /**
     * 匿名内部类
     */
       new Thread(){
            @Override
            public void run() {
                //线程执行的内容
            }
        }.start();

6.线程分为守护线程和用户线程

用户线程:当一个进程不包含任何存货的用户线程时,进行结束(平时创建的都是用户线程,如mian)

守护线程:守护用户线程,当最后一个用户线程结束时,守护线程自动死亡(创建完用户线程时。调用Thread的setDaemon(true)方法,即可改为守护线程)

7.显式锁 和 隐式锁的区别

(1)出生不同

Sync:Java中的关键字,是由JVM来维护的。是JVM层面的锁。

Lock:是JDK5以后才出现的具体的类。使用lock是调用对应的API。是API层面的锁

sync是底层是通过monitorenter进行加锁(底层是通过monitor对象来完成的,其中的wait/notify等方法也是依赖于monitor对象的。只有在同步块或者是同步方法中才可以调用wait/notify等方法的。因为只有在同步块或者是同步方法中,JVM才会调用monitory对象的);通过monitorexit来退出锁的。

而lock是通过调用对应的API方法来获取锁和释放锁的

(2)使用方式不同:所谓的显示和隐式就是在使用的时候,使用者要不要手动写代码去获取锁和释放锁的操作。

(3)等待是否中断

Sync是不可中断的。除非抛出异常或者正常运行完成

Lock可以中断的。中断方式:

	1:调用设置超时方法tryLock(long timeout ,timeUnit unit)

	2:调用lockInterruptibly()放到代码块中,然后调用interrupt()方法可以中断

(4)加锁的时候,是否可以公平

Sync;非公平锁

lock:两者都可以的。默认是非公平锁。在其构造方法的时候可以传入Boolean值。

	true:公平锁

	false:非公平锁

(5)锁绑定多个条件来condition

Sync:没有。要么随机唤醒一个线程;要么是唤醒所有等待的线程。

Lock:用来实现分组唤醒需要唤醒的线程,可以精确的唤醒,而不是像sync那样,不能精确唤醒线程。

8.第三种多线程类Callable

有返回值时,当主线程调用get()方法,主线程进入等待状态,直到有结果后主线程再继续执行

9.Thread.Statue

线程状态。 线程可以处于以下状态之一:

	NEW 	
	尚未启动的线程处于此状态。 

	RUNNABLE 
	在Java虚拟机中执行的线程处于此状态。 

	BLOCKED 
	被阻塞等待监视器锁定的线程处于此状态。 

	WAITING 
	无限期等待另一个线程执行特定操作的线程处于此状态。

	TIMED_WAITING 

	正在等待另一个线程执行最多指定等待时间的操作的线程处于此状态。 
	TERMINATED 
	已退出的线程处于此状态。 

	线程在给定时间点只能处于一种状态。 这些状态是虚拟机状态,不反映任何操作系统线程状态。

10.线程池

Java中的四种线程池. ExecutorService,一定时间后会自动关闭

(1) 缓存线程池

/** 缓存线程池. 
* (长度无限制) 
* 执行流程: 
* 1. 判断线程池是否存在空闲线程 
* 2. 存在则使用 
* 3. 不存在,则创建线程 并放入线程池, 然后使用 
*/
    //创建线程池
      ExecutorService service = Executors.newCachedThreadPool();
      //执行线程池中的一个线程,传的是一个线程任务,不是线程
      service.execute(new Runnable() {
          @Override
          public void run() {
              //执行的任务
          }
      });

(2)定长线程池

/** 定长线程池. 
* (长度是指定的数值) 
* 执行流程:
* 	1. 判断线程池是否存在空闲线程 
*	2. 存在则使用 
* 	3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用 
*	4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程 
*/
  ic static void main(String[] args) {
      //创建一个固定线程池,长度为2
      ExecutorService service = Executors.newFixedThreadPool(2);
      service.execute(new Runnable() {
         //执行的任务
          }
      });

(3)单线程线程池

效果与定长线程池 创建时传入数值1 效果一致.

/*** 单线程线程池. 
* 执行流程: 
*	 1. 判断线程池的那个线程是否空闲 
*	 2. 空闲则使用 
*	 3. 不空闲,则等待 池中的单个线程空闲后 使用 
*/

(4)周期性任务定长线程池

	 /**
     * 1.    定时执行一次
     * 参数1.定时执行的任务
     * 参数2.时长数字
     * 参数3.时长数字的时间单位TimeUnit常量指定
     */
    ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
    service.schedule(new Runnable() {
          @Override
          public void run() {
              //执行的任务
          }
      },1, TimeUnit.SECONDS);
	 /**
     * 2.    周期性执行任务
     * 参数1.定时执行的任务(第一次执行在什么时间以后)
     * 参数2.延迟时长数字(每个多久执行一次)
     * 参数3.周期时长数字
     * 参数4.时长数字的时间单位,TimeUnit常量指定
     */
    ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
    service.scheduleAtFixedRate(new Runnable() {
          @Override
          public void run() {
              //执行的任务
          }
      },5,1,TimeUnit.SECONDS);

每个线程都有自己的栈空间,但共用一个堆内存##

程基础整理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值