Java 多线程 学习笔记

Java 线程

 

进程:一个程序;

线程:程序运行的基本执行单元;(Java中只有线程)

主线程:JVM调用程序main()所产生的线程;

当前线程:一般指通过Thread.currentThread()来获取的进程

后台线程:指为其他线程提供服务的线程,也称为守护线程。JVM的垃圾回收线程就是一个后台线程。用户线程和守护线程的区别在于,是否等待主线程依赖于主线程结束而结束。

前台线程:是指接受后台线程服务的线程,其实前台后台线程是联系在一起,就像傀儡和幕后操纵者一样的关系。傀儡是前台线程、幕后操纵者是后台线程。由前台线程创建的线程默认也是前台线程。可以通过isDaemon()和setDaemon()方法来判断和设置一个线程是否为后台线程。

守护线程

多任务

多进程

单线程

多线程

 

分时调度:是所有线程轮流获得CPU使用权,并平均分配每个线程占用CPU的时间;

抢占式调度:是根据线程的优先级别来获取CPU的使用权。JVM的线程调度模式采用了抢占式模式。

 

线程创建

继承Thread:继承Thread,重写run(),start()开启线程,调用run();

MyThread mt = new MyThread();

mt.start();

通过Runnable:实现Runnable接口,重写run();

MyRunnable mr = new MyRunnable();

Thread t = new Thread(mr);

t.start();

通过Callable 和 FutureTask:实现Callable接口,重写Call()

MyCallable mc new MyCallable();

FutureTask<String> ft = new FutureTask<>(mc);

Thread t = new Thread(ft);

t.start();

 

创建线程的三种方式的对比

采用实现Runnable、Callable接口的方式创见多线程时,

优势是:线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。

在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。

劣势是:编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。

 

使用继承Thread类的方式创建多线程时

优势是:编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。

劣势是:线程类已经继承了Thread类,所以不能再继承其他父类。

 

线程状态

新建状态(new):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread()

就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行。

运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。

阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。

根据阻塞产生的原因不同,阻塞状态又可以分为三种

等待阻塞:运行状态中的线程执行wait()方法;wait()、await()、singnal()

同步阻塞:线程在获取synchronized同步锁失败(因为锁被其他线程所占用),它会进入同步阻塞状态;

其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

死亡状态(Dead):线程执行完了或者因异常退出run()方法,该线程结束生命周期。

只有就绪状态才能进入运行状态start启动线程,run调用方法

 

Java线程阻塞的主要方法

Join():让一个线程等待另一个线程完成才继续执行,可使异步线程变为同步线程,join方法是不会释放锁。如A线程线程执行体中调用B线程的join()方法,则A线程被阻塞,知道B线程执行完为止,A才能得以继续执行。

sleep() :让当前的正在执行的线程暂停指定的时间,并进入阻塞状态。在其睡眠的时间段内,该线程由于不是处于就绪状态,因此不会得到执行的机会。即使此时系统中没有任何其他可执行的线程,出于sleep()中的线程也不会执行。因此sleep()方法常用来暂停线程执行。

setDaemom:设置后台线程:调用Thread对象的setDaemon(true)方法可以将指定的线程设置为后台线程。判断线程是否是后台线程:调用thread对象的isDeamon()方法

setPriority:设置线程优先级:setPriority(int priorityLevel)。参数priorityLevel范围在1-10之间,常用的有如下三个静态常量值:MAX_PRIORITY:10,MIN_PRIORITY:1NORM_PRIORITY:5,获取线程优先级:getPriority()。

yield():线程让步,yield()方法还与线程优先级有关,当某个线程调用yiled()方法从运行状态转换到就绪状态后,CPU从就绪状态线程队列中只会选择与该线程优先级相同或优先级更高的线程去执行。

interrupt():中断线程,被中断线程会抛InterruptedException。

wait():等待获取锁:表示等待获取某个锁执行了该方法的线程释放对象的锁,JVM会把该线程放到对象的等待池中。该线程等待其它线程唤醒 。

notify():执行该方法的线程唤醒在对象的等待池中等待的一个线程,JVM从对象的等待池中随机选择一个线程,把它转到对象的锁池中。使线程由阻塞队列进入就绪状态。

 

线程类的一些常用方法

1、sleep(): 强迫一个线程睡眠N毫秒。

2、isAlive(): 判断一个线程是否存活。 

3、join(): 等待线程终止。 

4、activeCount(): 程序中活跃的线程数。

5、enumerate(): 枚举程序中的线程。

6、currentThread(): 得到当前线程。

7、isDaemon(): 一个线程是否为守护线程。

8、setDaemon(): 设置一个线程为守护线程。

(用户线程和守护线程的区别在于,是否等待主线程依赖于主线程结束而结束)

9、setName(): 为线程设置一个名称。

10、wait(): 强迫一个线程等待。

11、notify(): 通知一个线程继续运行。 

12、setPriority(): 设置一个线程的优先级。

 

synchronized:可作用于变量、方法、代码块,同步函数的锁是this,static同步函数的锁是Class对象(类名.class)

volatile:volatile相当于synchronized的弱实现,也就是说volatile实现了类似synchronized的语义,却又没有锁机制。它确保对volatile字段的更新以可预见的方式告知其他的线程。只作用于变量。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值