Java线程如何定义
小编给大家分享一下Java线程如何定义,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
定义线程
定义一个实现 Runnable 接口的类 A, 并实现该接口中的 run 方法, 最后实例化类 A, 作为 Thread 类的构造参数。
// 定义一个实现 Runnable 接口的类 A, 并实现该接口中的 run 方法public class A implements Runnable { [@Override](https://my.oschina.net/u/1162528) public void run() { System.out.println("开启一个县城... "); }}// 实例化类 AA task = new A();// 作为 Thread 类的构造参数。 Thread t = new Thread(task);
定义一个继承 Thread 类的类 A, 并重写类 A 的 run 方法
注意: 其实还是 Runnable 接口中 run 方法,因为 Thread 类实现了 Runnable接口
// 定义一个继承 Thread 类的类 A, 重写类 A 的 run 方法public class A extends Thread { [@Override](https://my.oschina.net/u/1162528) public void run() { System.out.println(); }}Thread t = new Thread();
其他:通过线程池 或者 实现Callable接口的方法。 暂时不多做介绍
通过实现 Runnable 接口与继承 Thread 类定义线程的区别
Runnbale 接口的实现类必须重写 run() 方法, 而 Thread类 的实现类有默认实现的run方法
Runnbale 接口的实现类并不是真正的线程类, 他只是执行线程的一个任务类
Thread 类要想以线程的方式执行run方法,只能依靠Thread类
继承 Thread 类会造成单继承的局限性
线程的生命周期
线程的生命周期指的是从线程的创建到启动直到结束。
java 线程的 6 种状态
注意: 这里说的是 java 线程的状态,并非操作系统的线程状态
Thread 类中通过枚举定义了线程的状态
public enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED;}
New:new Thread() 后线程的状态就是新建。
Runnable:线程一旦调用 start() 方法,无论是否运行,状态都为 Runable, Runable 状态指示表示线程可以运行,不表示线程当下一定在运行,线程是否运行由虚拟机所在操作系统调度决定。
BLOCKED:线程试图获取一个内部对象的 Monitor(进入synchronized方法或synchronized块)但是其他线程已经抢先获取,那此线程被阻塞,知道其他线程释放 Monitor 并且线程调度器允许当前线程获取到 Monitor,此线程就恢复到可运行状态。
WAITING:当一个线程等待另一个线程通知调度器一个条件时,线程进入等待状态。
TIMED_WAITING:和等待类似,某些造成等待的方法会允许传入超时参数,这类方法会造成计时等待,收到其他线程的通知或者超时都会恢复到可运行状态。
TERMINATED:线程执行完毕正常结束或执行过程中因未捕获异常意外终止都会是线程进入被终止状态
扩展
操作系统中线程的5中状态
新建
就绪
运行
阻塞
终止
线程调度
操作系统会给每个线程分配时间片, 在某一时刻只执行一个时间片的线程。每个java程序启动后, jvm会自动帮我们创建两个线程, 一个是main, 一个是GC
线程调度的实现方式
分时调度模型
让所有线程轮流获得CPU的控制权,并且为每个线程平均分配CPU时间片段
抢占式调度模型
选择优先级相对较高的线程执行,如果所有线程的优先级相同,则随机选择一个线程执行 Java虚拟机采用此种调度模型。
java 线程分类
用户线程
也称非守护线程, jvm会在所有非守护线程结束后随之离开
守护线程
也称作后台线程, 当进程中的所有 非后台线程 结束后, 后台线程也会随之结束。
如何设置后台线程
在线程启动前调用setDaemon()方法
为什么GC线程是守护线程?
因为当所有的非守护线程结束后, 也就不会产生垃圾, 那么GC线程也就没有存在的意义
线程安全问题
出现线程不安全的条件
必须存在两个或者两个以上的线程。
多个线程共享着一个资源,而且操作资源的代码有多句。
解决办法
1. 同步代码块
使用 synchronized 修饰代码块, 如下所示
public void methodA() { synchronized (this){ // doSomething }}
注意的事项:
锁对象可以是任意的一个对象。
锁对象必须是多个线程共享 的资源。
调用了sleep方法的线程并不会释放锁对象。
如果不存在着线程安全问题,千万不要使用同步代码块或者是同步函数, 因为会降低效率的。
2. 同步函数
使用synchronized修饰该函数则称作为同步函数, 如下所示。
public synchronized void methodA() { // doSomething }
注意的事项:
非静态同步函数的锁对象是this对象,静态函数的锁对象是当前所属类的class文件对象。
同步函数的锁对象是固定的,无法更改。
推荐使用: 同步代码块
同步代码块的锁对象可以由我们自己指定,同步函数的锁对象是固定的。
同步代码块可以随意指定那个范围需要被同步,而同步函数必须是整个函数都同步, 代码不灵活。
死锁
死锁出现的条件
必须存在两个及两个以上的线程
这些线程共享两个及两个以上的资源
多线程各自持有不同的锁,并试图获取对方已持有的锁
如何解决
以上是"Java线程如何定义"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!