Java多线程-Thread基础

摘抄并后查

 

1. 创建线程

  三种方式:一种继承 Thread 类,一种实现 Runnable 接口,一种实现 Callable 接口。

  一般建议使用 实现 Runnable 接口的,解决单继承的局限性。但是相比于 Runnable 接口,Callable 接口可以有返回值,可以抛出异常,但是需要 FutureTask 类的支持,用于接收运算的结果。

 

 

2. 线程运行结果与执行顺序无关

  线程的调度是由 CPU 决定,CPU执行子任务时间具有不确定性。

 

 

3. 线程实例变量与安全问题

  线程之间变量有共享和不共享之分,共享理解为大家都使用同一份,不共享理解为每个单独持有一份。

  共享变量在多个线程都操作的情况下会产生脏数据。解决方案,可以是在访问变量方法中增加 synchronized 关键字(含有 synchronized关键字的这个方法称为“互斥区”或“临界区”,只有获得这个关键字对应的锁才能执行方法体,方法体执行完会自动释放锁)。

 

 

4. 停止线程

  终止正在运行的线程方法有三种:

  1)使用退出标志,使线程正常的执行完 run 方法终止

  run 方法内部使用 while 循环,条件是退出标志,在合适的时候设置退出标志即可退出程序。但,可能会让 while 中的循环全部执行完,才能反应。

 

  2)使用 interrupt 方法,使线程异常,线程进行捕获或抛异常,正常执行完 run 方法终止

  使用 thread.interrupt() 对正在进行中的方法进行中断。 在 run 方法内部,对需要执行的代码块 try catch 一下,对 catch 到的 InterruptedException 进行退出循环处理。

  

  3)使用 stop 方法强制退出

  

 

5. 线程优先级

  线程优先级范围为 1-10,API 提供等级分为:低(MIN_PRIORITY = 1),中(NORM_PRIORITY = 5),高(MAX_PRIORITY = 10)。

  线程优先级有一下特点:

  1)继承特性,当线程中的run()方法代码里面又创建了一个新的线程对象时,新创建的线程优先级和父线程优先级一样.

  2)随机性(线程调度的顺序不一定是根据优先级,具有随机性)

 

 

6. 守护线程

  守护线程顾名思义是一个线程守护另一个线程【此线程为用户线程】,故守护的线程称为守护线程,被守护的线程称为用户线程。作用是为其他线程运行提供便利服务。例如,main 函数里面设置一个守护线程(thread.setDaemon(true)),那么当 main 线程退出后,守护线程也会自动退出,不管他是不是还在死循环中。。。

  

 

7. 线程中的 3 个方法

  1)sleep() 方法

  主要是让其他线程走,自己进行休眠,但是自己却不会释放对象锁,也就是说,如果有同步锁的时候,其他线程不能访问共享数据。

  该方法需要捕获异常,比如有两个线程同时执行(没有 Synchronized),一个线程优先级为 MAX_PRIORITY,另个为 MIN_PRIORITY,如果没有 sleep 方法,只有高优先级的线程执行完后,低优先级的线程才能执行,但是当高优先级的线程 sleep(5000) 后,低优先级的就有机会执行了,总之, sleep() 可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程有执行的机会。

 

  2)yield() 方法

  Thread 类的静态方法。 其也是一个休眠自身线程的方法,同样不会释放自身锁的标识,区别在于他是没有参数的,即 yield 方法只是使当前线程重新回到可执行状态。所以执行 yield() 的线程有可能在进入到可执行状态后马上又被执行,另外, yield() 方法只能使同优先级或者高优先级的线程得到执行机会,这点和 sleep() 方法不同。

  yield 方法可以很好的控制多线程,如在执行某项复杂的任务时,如果担心占用资源过多,可以在完成某个重要的工作后使用 yield 方法,让掉当前 CPU 的调度权,等下次获取到再继续执行,这样不但能完成自己的重要工作,也能给其他线程一些运行的机会,避免一个线程长时间占有 CPU 资源。

 

  3)join() 方法

  thread.join() 方法让一个线程 “加入” 到另外一个线程的尾部。在这个线程执行完毕之前,另个线程不能工作。即,等待这个线程执行完毕。

 

 

8. wait()、 notify()、notifyAll() 方法

  wait() 与 notify / notifyAll 方法必须在同步代码块中使用,即要先调用对象加锁,

  1)当前线程调用共享对象的 wait() 方法时,当前线程只会释放当前共享对象的锁,当前线程持有的其他共享对象的锁并不会被释放(obj.wait() 时释放 obj 的锁,其他不会释放);当一个线程调用共享对象的 wait() 方法被挂起后,如果其他线程中断了该线程,则该线程会抛出 InterruptedException 异常并返回

  2)当执行 notify / notifyAll 方法时,会唤醒一个处于等待该对象锁的线程,然后继续往下执行,直到执行完退出对象锁锁住的区域(Synchronized修饰的代码块)后再释放锁。这里,notify / notifyAll 执行后,并不立即释放锁,而是要等到执行完临界区中代码后,再释放。故,在实际编程中,我们应该尽量在线程调用 notify / notifyAll 后,立即退出临界区,即不要在 notify / notifyAll 后面再写一些耗时的代码。

  唤醒方法,除了 notify / notifyAll 之外,还可以通过 interrupt() 方法以抛出异常的方式唤醒!

 

 

9. 线程运行状态

 

 

 

posted @ 2020-03-12 17:25  停不下的时光  阅读(289)  评论(0编辑  收藏  举报