线程相关简介

1. 学习线程首先要理清楚三个概念:

    a. 进程:进程是一个静态的概念

    b. 线程:一个进程里面有一个主线程叫main()方法,是一个程序里面的,一个进程里面不同的执行路径。

    c. 在同一个时间点上,一个CPU只能支持一个线程在执行。因为CPU运行的速度很快,因此我们看起来的感觉就像是多线程一样。

  什么才是真正的多线程?如果你的机器是双CPU,或者是双核,这确确实实是多线程。

2. 线程:依赖与进程的执行绪,是程序使用CPU的基本单位

进程:正在运行的程序,代表一个应用程序在内存中的区域

多线程:用一个进程中,多个线程执行,多个线程共享进程的资源(堆内存,方法区) 占内存独立。

进程和线程的区别?

(1)进程是资源的分配和调度的一个独立单元,而线程是CPU调度的基本单元

(2)同一个进程中可以包括多个线程,并且线程共享整个进程的资源(寄存器、堆栈、上下文),一个进行至少包括一个线程。

(3)进程的创建调用fork或者vfork,而线程的创建调用pthread_create,进程结束后它拥有的所有线程都将销毁,而线程的结束不会影响同个进程中的其他线程的结束

(4)线程是轻两级的进程,它的创建和销毁所需要的时间比进程小很多,所有操作系统中的执行功能都是创建线程去完成的

(5)线程中执行时一般都要进行同步和互斥,因为他们共享同一进程的所有资源

(6)线程有自己的私有属性TCB,线程id,寄存器、硬件上下文,而进程也有自己的私有属性进程控制块PCB,这些私有属性是不被共享的,用来标示一个进程或一个线程的标志.

3. Java(线程调度模型了解)

抢占式调度模型:优先让优先级高的使用,如果优先级相同,随机一个

4. Jvm支持多线程:至少启动了主线程和垃圾回收机制

Java命令(java.exe)启动虚拟机,启动虚拟机线程与启动一个应用程序,该进程启动主进程,主线程调用main方法(main方法就在主线程)

5. 线程的创建,

创建线程的四种方式

两种方法分析:

方法一继承Thread

    a.将类声明为 Thread 的子类

    b.该子类应重写 Thread 类的 run 方法

    c.接下来可以分配并启动该子类的实例。

好处:可以直接使用Thread类中的方法,代码简单

弊端:如果已经有了父类,就不能用这种方法

多个线程无法共享数据,使用static可以实现共享数据,但是生命周期过长,使用继承局限类

方法二实现Runnable接口(推荐使用)

    a. 定义一个类实现Runnable;

 b.重写run方法;

    c.创建Runnable的子类对象;要启动一个新的线程就必须new一个Thread对象出来(Runnable target)。{不开启新线程直接调用run方法,这个称为方法调用,方法调用的执行是等run()方法执行完之后才会继续执行main()方法}

    d.将其当作参数传递给Thread的构造函数;

    e. t.start()开启线程;启动新开辟的线程,新线程执行的是run()方法,新线程与主线程会一起并行执行,运行顺序随机

好处:即使自己定义的线程类有父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的,扩展性强

弊端:不能直接使用Thread中的方法,需要先获取到线程对象后,才能得到Thread的方法,代码复杂

将业务与线程概念分离,多个线程共享业务的数据实现,避免单继承的局限性

因为接口的实现可以实现多个,而类的继承只能是单继承。因此在开辟新线程时能够使用Runnable接口就尽量不要使用从Thread类继承的方式来开辟新的线程。

#查看源码:

A. 看Thread类的构造函数,传递了Runnable接口的引用;

B. 通过init()方法找到传递的target给成员变量的target赋值,this.target=target;

C. 查看run方法,发现run方法中有判断,如果target不为null,就会调用Runnable接口子类对象的run方法;

#查看源码的区别:

A. 继承Thread:由于子类重写了Thread类的run(),当调用start()时,直接找子类的run()方法;

实现Runnable:构造函数中传入了Runnable的引用,成员变量记住了它,start()调用run()方法时内部判断成员变量Runnable的引用是否为空,不为空编译时看的是Runnable的run(),运行时执行的是子类的run()方法。

6. Thread 类中的 start () 和 run () 方法有什么区别?

这个问题经常被问到,但还是能从此区分出面试者对 Java 线程模型的理解程度。start ()方法被用来启动新创建的线程,而且 start ()内部调用了 run ()方法,这和直接调用 run ()方法的效果不一样。当你调用 run ()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start ()方法才会启动新线程。

7.  线程中常用的一些方法

A.线程优先级:抢占CPU资源的能力,优先级越高,抢占CPU的可能性越大

int getPriority():返回线程优先级

public final void setPriority(int newPriority):更改线程优先级

B. 线程休眠:sleep()相当于葵花点穴手点穴一小时。

public static void sleep(long millis):在指定的毫秒数内让当前正在执行的线程休眠(暂停运行); 使当前线程(即调用该方法的线程)暂停该执行一段时间,让其他线程更有机会继续执行,但它并不释放锁资源,也就是说如果有synchroinzed同步块,其他线程仍然不能访问共享数据,注意该方法要捕捉异常。

如果没有sleep()方法,只有高优先级的线程执行完以后,低优先级的线程才能执行,但是高优先级的线程sleep(5000)后,低优先级就有机会执行。

sleep()方法是在Thread类里面声明的一个静态方法,因此可以使用Thread.sleep()的格式进行调用。

总之,sleep可以使低优先级的线程有执行的机会。

C. wait()相当于只要点穴就一直等待

D. 使用interrupt()方法去结束掉一个线程的执行并不是一个很好的做法!

    睡眠的时如果被打断就会抛出InterruptedException异常 当发生InterruptedException时,直接把循环的条件设置为false即可退出死循环, 继而结束掉子线程的执行,这是一种比较好的结束子线程的做法;

     调用interrupt()方法把正在运行的线程打断,相当于是主线程一盆凉水泼上去把正在执行分线程打断了,分线程被打断之后就会抛InterruptedException异常,这样就会执行return语句返回,结束掉线程的执行。

E. public final void join():等待该线程终止。线程插队!!!调用该方法代码所在的线程,等待调用方法的线程结束再运行

匿名内部类在使用它所在方法中的局部变量时,这个局部变量要用final修饰

F. public final void setDaemon(boolean on)将该线程标记为守护线程或用户线程。on为true标记为守护线程,当正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调用。

G. yield():它是一个静态方法而且只保证当前线程放弃 CPU 占用而不能保证使其它线程一定能占用 CPU,执行 yield ()的线程有可能在进入到暂停状态后马上又被执行。

H. Java 中 notify 和 notifyAll 有什么区别?

这又是一个刁钻的问题,因为多线程可以等待单监控锁,Java API 的设计人员提供了一些方法当等待条件改变的时候通知它们,但是这些方法没有完全实现。notify ()方法不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有用武之地。而 notifyAll ()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行。

I: Java 程序中 wait 和 sleep 都会造成某种形式的暂停,它们可以满足不同的需要。wait ()方法用于线程间通信,如果等待条件为真且其它线程被唤醒时它会释放锁,而 sleep ()方法仅仅释放 CPU 资源或者让当前线程停止执行一段时间,但不会释放锁。

8. 并发和并行

并行指边吃饭边打电话。体现的是同时处理多个任务的能力

并发指先停止吃饭接电话,打完再接着吃。具有处理多个任务的能力,不一定是同时

9. 车站买票

线程安全问题:

1.线程随机访问性

2.多个线程并行

3.多个线程共享数据

4.多个线程操作了共享数据

处理方式:使用java同步机制将县城和跟踪的某一段代码看成一个完整的整体,当代码执行完成之后,其他线程才能占用

原子性:在执行代码时,把一个完整动作称为一个原子,不可分割,不可打断

10. synchronized(锁对象){//任意对象

同步代码块}

锁对象:多个线程使用相同的锁对象进行同步机制,如果使用不同的锁对象无法完成同步机制

同步代码块锁对象:任意对象

同步方法的锁对象:当前对象  this

静态同步方法的锁对象:当前类

11. 单例设计模式

饿汉式与懒汉式的区别

1.饿汉式:空间换时间

2.懒汉式:时间换空间,多线程访问时,线程阻塞可能创建多个对象

饿汉式

class Singleton{

    //1.私有构造方法,其他类不能访问该构造方法

    private Singleton(){
    }

    //2.创建本类对象,Singleton s成员变量用对象.调用,没有对象,只能加static调用

    private static Singleton s=new Singleton();

    //3.对外提供公共的访问方法

    public static Singleton getInstance(){//获取实例

        return s;

    }

}

懒汉式:单例的延迟加载模式

class Singleton {

    //1.私有构造方法,其他类不能访问该构造方法
    private Singleton() {
    }
    //2.创建本类对象,Singleton s成员变量用对象.调用,没有对象,只能加static调用
    private static Singleton s = new Singleton();
    //3.对外提供公共的访问方法
    public static Singleton getInstance() {//获取实例
        if (s == null) {
            //线程1等待,线程2等待。。。
            s = new Singleton();
        }
        return s;
    }
}

12. synchronized、volatile、CAS比较

synchronized是悲观锁,属于抢占式,会引起其他线程阻塞。

volatile提供多线程共享变量可见性和禁止指令重排序优化。

volatile 是一个特殊的修饰符,只有成员变量才能使用它。在 Java 并发程序缺少同步类的情况下,多线程对成员变量的操作对其它线程是透明的。volatile 变量可以保证下一个读取操作会在前一个写操作之后发生

CAS是基于冲突检测的乐观锁(非阻塞)。CAS指令的语义是“我认为V的值应该为A,如果是,那么将V的值更新为B,否则不修改并告诉V的值实际为多少”

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值