Java 线程

进程与线程:

·进程:具有一定独立功能的程序关于某个数据集合上的一次运行活动。进程是系统进行资源分配和调度的一个独立单位。

·线程:进程的一个实体,是CPU调度的基本单位。是比进程更小的能够独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

·进程与线程的关系线程是属于进程的,线程运行在进程空间内,同一进程所产生的的线程共享同一用户内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。所以,线程不能独立地执行,它必须依附在一个运行的应用程序上(即进程上),而一个进程至少需要一个线程作为它的指令执行,进程管理着资源(比如CPU、内存、文件等等),而将线程分配到某个CPU上执行

·


实现线程的三种方式:

·继承Thread类,重写run()方法,run()方法代表线程要执行的任务。

  实现Runnable接口,重写run()方法,run()方法代表线程要执行的任务。

  实现callable接口,重写call()方法,call()作为线程的执行体,具有返回值,并且可以对异常进行声明和抛出。

·由于Java单继承的关系,如果一个类已经继承了某个类,则无法继承Thread类,此时只能通过实现Runnable接口来实现多线程。

·获取当前线程名:如果线程类继承Thread类,可以通过this.getName()获取当前线程,this也可以省略;也可以通过

Thread.currentThread().getName()来获取当前线程。
如果线程类实现Runnable接口,也可以通过Thread.currentThread().getName()来获取当前线程。

线程的start方法与run方法:

·start()方法:1.启动了线程;2.让JVM调用了run方法;

start方法最本质的功能是从CPU中申请另一个线程空间来执行run方法中的代码,它与当前线程是两条线,在相对独立的线程空间运行,调用start方法后run方法里的代码会和当前线程并发或并行执行。

·run()方法:存放的是线程要运行的代码。

·总结:new一个Thread,线程进入了新建状态,调用start()线程进入就绪状态,分配到时间片就可以运行。

start()会执行线程的相关准备工作,然后自动执行run()方法里的内容,是真正的多线程工作

如果直接执行run()方法,就会把run()方法当做一个普通方法去执行,并不会在某个线程中执行它,不是多线程工作。

·


线程同步:

·多个线程在同一个时间段内只能有一个线程执行指定的代码,其他线程要等待此线程完成之后才可以继续执行。是为了让多个线程能够协调地并发运行

·同步实现方法1.同步方法即有synchronized关键字修饰的方法;

                     2.同步代码块即有synchronized关键字修饰的语句块

                     3.使用特殊域变量(volatile)实现线程同步          

                        a.volatile关键字为域变量的访问提供了一种免锁机制;

                        b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新;

                        c.因此每次使用该域就要重新计算,而不是使用寄存器中的值 ;

                        d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量 。

                     4.使用重入锁实现线程同步

                     5.使用局部变量来实现线程同步

·volatile:修饰变量;不会造成线程阻塞;保证内存可见性(从主存中读取数据,修改的数据保存到主存中),不保证操作原子性

              应用场景:1.对变量的写操作不依赖于当前值;

                            2.该变量没有包含在具有其他变量的不变式中。

synchronized:修饰变量与方法;可能会造成线程阻塞;保证内存可见性与操作原子性。

·


Thread类与Object类:

·Thread类的方法:start/yield/sleep/join/interrupt等,属于线程级别的方法。

start:创建一个新线程。

join使当前线程等待调用join()方法的线程结束后才能继续执行,即将两个交替执行的线程合并为顺序执行的线程。

interrupt设置线程的中断标志。

sleepsleep()方法需要指定等待的时间,它可以让当前正在执行的线程在指定的时间内暂停执行,进入阻塞状态,该方法可以让其他线程(没有优先级限制)得到执行的机会。但是sleep()方法不会释放“锁标志”,也就是说如果有synchronized同步块,其他线程仍然不能访问共享数据。 

yield与sleep()类似,不会释放“锁标志”,但不指定暂停时线程进入就绪状态,只能让同优先级或更高优先级的线程有执行的机会

·Object类的方法:wait/notify/notifyAll,属于对象的方法,wait、notify、notifyAll只能在同步控制方法或同步控制块中使用

wait:使当前线程暂停执行并释放对象锁标示将当前线程放入对象等待池中,可以指定时间也可以不指定时间。

notify对象等待池中移出任意一个线程并放入锁标志等待池中,只有锁标志等待池中的线程可以获取锁标志,它们随时准备争夺锁的拥有权。

notifyAll:当调用了某个对象的notifyAll()方法,会将对象等待池中的所有线程都移动到该对象的锁标志等待池。 

·wait()与sleep()的区别

wait:来自Object类,可以指定时间也可以不指定时间,线程会释放执行权、释放锁

sleep:来自Thread类,指定时间,线程会释放执行权,不会释放锁

·


线程停止:

·使用退出标志,使线程正常退出,也就是当 run 方法完成后线程终止;

  通过Thread类的interrupt方法,两种情况:

(1)线程处于阻塞状态,如使用了sleep方法。

(2)使用while(!isInterrupted()){……}来判断线程是否被中断。

    在第一种情况下使用interrupt方法,sleep方法将抛出一个InterruptedException异常,而在第二种情况下线程将直接退出。

调用线程类的interrupted方法,其本质只是设置该线程的中断标志,将中断标志设置为true,并根据线程状态决定是否抛出异常

若线程在阻塞状态时,调用了它的interrupt()方法,那么它的“中断状态”会被清除并且会收到一个InterruptedException异常。例如,线程通过wait()进入阻塞状态,此时通过interrupt()中断该线程;调用interrupt()会立即将线程的中断标记设为“true”,但是由于线程处于阻塞状态,所以该“中断标记”会立即被清除为“false”,同时,会产生一个InterruptedException的异常。
如果线程被阻塞在一个Selector选择器中,那么通过interrupt()中断它时;线程的中断标记会被设置为true,并且它会立即从选择操作中返回。
如果不属于前面所说的情况,那么通过interrupt()中断线程时,它的中断标记会被设置为“true”。
中断一个“已终止的线程”不会产生任何操作。

·


ThreadLocal:

·多线程环境下,之所以会有并发问题,是因为不同的线程会同时访问同一个共享变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,让每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本每个线程维护一个 ThreadLocalMap 的映射表,映射表的 key 是 ThreadLocal 实例本身,value 是要存储的副本变量。ThreadLocal 实例本身并不存储值,它只是提供一个在当前线程中找到副本值的 key。

·一篇详细理解的文章:ThreadLocal详解

·


多线程同步与异步:

·线程同步A线程要请求某个资源,但是此资源正在被B线程使用中,因为同步机制存在,A线程请求不到,怎么办,A线程只能等待下去。

·线程异步:A线程要请求某个资源,但是此资源正在被B线程使用中,因为没有同步机制存在,A线程仍然请求的到,A线程无需等待。

·


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值