Java中三种创建线程方式以及相关知识点简述

线程与进程:

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

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

线程的基本状态:

        

 

        新建状态:当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. 当一个线程执行的代码出现异常时,其所持有的锁会自动释放
  • 不会由于异常导致出现死锁现象~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值