大家好,欢迎来到 Java 小助手的线程教学课程!今天,我们将深入探讨 Java 中线程的方方面面,从基础的线程介绍到高阶技术的线程同步和状态,让你真正掌握多线程编程的精髓。准备好迎接线程世界的挑战了吗?让我们开始吧!🧵🔄
1. 线程介绍
首先,让我们从线程的基础入手。了解如何创建线程、线程的生命周期以及如何合理运用多线程提升程序性能。通过本节,你将能够轻松驾驭 Java 多线程编程。
创建线程的两种方式:
(1)继承 Thread 类
通过继承 Thread
类,我们可以创建一个新的线程。需要重写 run
方法,该方法中包含了线程的执行逻辑。
class MyThread extends Thread {
public void run() {
// 线程执行的代码
}
}
// 创建并启动线程
MyThread myThread = new MyThread();
myThread.start();
myThread.start();
(2)实现 Runnable 接口
另一种创建线程的方式是实现 Runnable
接口。这样可以更好地避免 Java 单继承的限制,同时提高代码的可维护性。
class MyRunnable implements Runnable {
public void run() {
// 线程执行的代码
}
}
// 创建线程并传入实现了 Runnable 接口的对象
Thread thread = new Thread(new MyRunnable());
thread.start();
通过实现Runnable接口,使得该类有了多线程类的特征。run()方法是多线程程序的一个执行目标。所有的多线程代码都在run方法里面。Thread类实际上也是实现了Runnable接口的类。
在启动的多线程的时候,需要先通过Thread类的构造方法Thread(Runnable target) 构造出对象,然后调用Thread对象的start()方法来运行多线程代码。
实际上所有的多线程代码都是通过运行Thread的start()方法来运行的。因此,不管是继承Thread类还是实现Runnable接口来实现多线程,最终还是通过Thread的对象的API来控制线程的,熟悉Thread类的API是进行多线程编程的基础。
tips:Runnable对象仅仅作为Thread对象的target,Runnable实现类里包含的run()方法仅作为线程执行体。而实际的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run()方法。
学习目标: 理解线程的基本概念,掌握线程的创建和启动方法。
Thread和Runnable的区别:
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
总结:
实现Runnable接口比继承Thread类所具有的优势:
1. 适合多个相同的程序代码的线程去共享同一个资源。
2. 可以避免java中的单继承的局限性。
3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。
扩充:在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个JVM其实在就是在操作系统中启动了一个进程。
2. 线程同步
学习线程同步的原因:
线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
在多线程环境下,线程同步是一个必须要解决的问题。学习关键字 synchronized
和 Lock
接口的使用,掌握如何避免数据竞争和保持数据一致性。
当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题。要解决多线程并发访问一个资源的安全性问题,Java中提供了同步机制(synchronized)来解决。
// 使用 synchronized 实现同步方法
public synchronized void synchronizedMethod() {
// 同步代码块
}
// 使用 Lock 接口实现同步
Lock lock = new ReentrantLock();
public void lockExample() {
lock.lock();
try {
// 同步代码块
} finally {
lock.unlock();
}
}
同步锁:
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.
1. 锁对象 可以是任意类型。
2. 多个线程对象 要使用同一把锁。
注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着(BLOCKED)。
同步方法:
使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。
Lock锁
java.util.concurrent.locks.Lock 机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。
Lock锁也称同步锁,加锁与释放锁方法化了,如下:
public void lock() :加同步锁。
public void unlock() :释放同步锁。
示例代码:
public class Ticket implements Runnable{
private int ticket = 100;
Lock lock = new ReentrantLock();
/*
* 执行卖票操作
*/
@Override
public void run() {
//每个窗口卖票的操作
//窗口 永远开启
while(true){
lock.lock();
if(ticket>0){//有票 可以卖
//出票操作
//使用sleep模拟一下出票时间
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto‐generated catch block
e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name+"正在卖:"+ticket‐‐);
}
lock.unlock();
}
}
}
学习目标: 掌握线程同步的基本原理和常用方法,避免多线程环境下的数据安全问题。
3. 线程状态
了解线程在运行过程中的状态对于调试和优化程序非常重要。学习不同线程状态的转换以及如何获取线程的状态信息。
当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,有几种状态呢?在API中 java.lang.Thread.State 这个枚举中给出了六种线程状态:
这里先列出各个线程状态发生的条件
线程状态一览:
-
新建(New): 线程被创建但还未启动。
-
就绪(Runnable): 线程已经被创建且可以运行,等待获取 CPU 时间片。
-
运行(Running): 线程正在执行。
-
阻塞(Blocked): 线程被阻塞,等待获取一个排它锁。
-
等待(Waiting): 线程进入等待状态,等待其他线程通知唤醒。
-
超时等待(Timed Waiting): 在等待状态的基础上设置了超时时间。
-
终止(Terminated): 线程执行完毕或者因异常退出,进入终止状态。
// 获取线程状态
Thread.State state = thread.getState();
System.out.println("线程状态:" + state);
一条有意思的tips:
我们在翻阅API的时候会发现Timed Waiting(计时等待) 与 Waiting(无限等待) 状态联系还是很紧密的,比如Waiting(无限等待) 状态中wait方法是空参的,而timed waiting(计时等待) 中wait方法是带参的。这种带参的方法,其实是一种倒计时操作,相当于我们生活中的小闹钟,我们设定好时间,到时通知,可是如果提前得到(唤醒)通知,那么设定好时间在通知也就显得多此一举了,那么这种设计方案其实是一举两得。如果没有得到(唤醒)通知,那么线程就处于Timed Waiting状态,直到倒计时完毕自动醒来;如果在倒计时期间得到(唤醒)通知,那么线程从Timed Waiting状态立刻唤醒。
学习目标: 能够通过获取线程状态更好地理解和调试多线程程序。
4. 互动结语
在这个丰富的线程知识之旅中,你掌握了哪些有趣的技能?有没有遇到令人挑战的问题?留言告诉我吧!在这个互动环节,我们将一同分享经验,共同进步!💬✨
📘 更多学习资源
想要更深入地学习线程的高级技术?推荐(微信搜索:gh_3aeecc6ab938(公众号)获取相关课程资源。
🔗 深度学习
欢迎查阅 Java 官方文档以及参与线程相关的技术社区,与其他开发者分享经验,解决问题。在这个广阔而有趣的线程世界,让我们一同深度学习!欢迎讨论分享。
学习目标: 激发学习兴趣,深入学习线程的更多高级应用和技术。
#Java编程 #多线程 #线程同步 #线程状态 #程序性能 #技术分享 #编程深度解析
J2EE7