线程与进程:

        进程作为资源分配的基本单位

        线程作为资源调度的基本单位,是程序的执行单元,执行路径(单线程:一条执行路径,多线程:多条执行路径)。是程序使用CPU的最基本单位。

线程的基本状态:

        

android java主线程更新ui java默认线程_Java

 

        新建状态:当new创建线程对象时

        就绪状态(可运行状态)Runnable:

         调用start()方法后。所需资源都已经获取到,就差cpu资源。

         运行状态,时间片到了,cpu调度到其他线程,次线程处于就绪状态

        运行状态Running:就绪状态获取到cpu资源后进入到运行状态

        不可运行状态(等待状态,阻塞状态,休眠状态):线程等待某个资源,被某个资源阻塞,比如i/o

        终止状态:线程运行结束。

线程有5种基本操作:

        派生、阻塞、激活、 调度、 结束

采用继承Thread类方式:

        优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。
        缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。

采用实现Runnable接口方式:

        优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
        缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。

采用实现Callable接口方式:

        Runnable和实现Callable接口的方式基本相同,不过是后者执行call()方法有返回值可以throws异常,前者线程执行体run()方法无返回值不能throws异常,因此可以把这两种方式归为一种这种方式与继承Thread类的方法之间的差别如下:
        优点:线程只是实现Runnable或实现Callable接口,还可以继承其他类。这种方式下,多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。
        缺点:编程稍微复杂,如果需要访问当前线程,必须调用Thread.currentThread()方法。

sychronized锁

        synchronized是Java的一个关键字,它能够将代码块(方法)锁起来

  • 它使用起来是非常简单的,只要在代码块(方法)添加关键字synchronized,即可以实现同步的功能~
public synchronized void test() {
          
         // doSomething
             }        synchronized是一种互斥锁
  • 一次只能允许一个线程进入被锁住的代码块

        synchronized是一种内置锁/监视器锁

  • Java中每个对象都有一个内置锁(监视器,也可以理解成锁标记),而synchronized就是使用对象的内置锁(监视器)来将代码块(方法)锁定的! (锁的是对象,但我们同步的是方法/代码块)

synchronized作用

  • synchronized保证了线程的原子性。(被保护的代码块是一次被执行的,没有任何线程会同时访问)
  • synchronized还保证了可见性。(当执行完synchronized之后,修改后的变量对其他的线程是可见的)

Java中的synchronized,通过使用内置锁,来实现对变量的同步操作,进而实现了对变量操作的原子性和其他线程对变量的可见性,从而确保了并发情况下的线程安全。

synchronized用法

        synchronized一般我们用来修饰三种东西:

  • 修饰普通方法
  • 修饰代码块
  • 修饰静态方法

重入锁

        我们来看下面的代码:        

public class Widget {

             // 锁住了
             public synchronized void doSomething() {
                ...
             }
         }
         
        public class LoggingWidget extends Widget {

             // 锁住了
             public synchronized void doSomething() {
                System.out.println(toString() + ": calling doSomething");
                super.doSomething();
             }
          }
  1. 当线程A进入到LoggingWidget的doSomething()方法时,此时拿到了LoggingWidget实例对象的锁
  2. 随后在方法上又调用了父类Widget的doSomething()方法,它又是被synchronized修饰
  3. 那现在我们LoggingWidget实例对象的锁还没有释放,进入父类Widget的doSomething()方法还需要一把锁吗?

        不需要的!

        因为锁的持有者是线程,而不是调用。线程A已经是有了LoggingWidget实例对象的锁了,当再需要的时候可以继续开锁进去的!

这就是内置锁的可重入性。记住,持有锁的是线程

释放锁的时机

  1. 当方法(代码块)执行完毕后会自动释放锁,不需要做任何的操作。
  2. 当一个线程执行的代码出现异常时,其所持有的锁会自动释放
  • 不会由于异常导致出现死锁现象~