Java多线程编程中的常用函数总结
Java多线程编程是实现高并发的基础,为了编写高效的多线程程序,需要掌握一些常用的多线程函数。本文将对Java多线程编程中的一些常用函数进行总结,涵盖线程的创建、互斥与同步、线程通信、线程状态控制等几个方面。
### 线程的创建、启动与终止
#### 创建线程
Java提供了两种创建线程的方式:继承Thread类和实现Runnable接口。其中,实现Runnable接口具有更好的扩展性和代码复用性,因为Java不支持多重继承,而实现接口可以避免这个问题。
// 通过继承Thread类创建线程
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread is running");
}
}
// 通过实现Runnable接口创建线程
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("MyRunnable is running");
}
}
public static void main(String[] args) {
// 创建线程
MyThread myThread = new MyThread();
MyRunnable myRunnable = new MyRunnable();
// 启动线程
myThread.start();
new Thread(myRunnable).start();
}
#### 启动线程
线程创建后必须调用start()方法才能启动线程。start()方法会自动调用run()方法,启动新线程,使其进入就绪状态。不能直接调用run()方法,这样虽然会执行run()方法中的代码,但并不会创建新线程,只是在当前线程上运行run()方法的代码而已。
// 启动线程 myThread.start(); new Thread(myRunnable).start();
#### 线程的终止
Java提供了四种方式来终止线程:正常退出、使用标志变量、使用Interrupt()方法、使用stop()方法。其中,使用stop()方法已经被弃用,不再推荐使用。
正常退出是指在run()方法中执行完所有的语句后自动结束线程。使用标志变量可以使线程在正常退出前结束循环,这是一种比较安全的线程终止方法。使用Interrupt()方法可以中断线程的阻塞状态,使其进入就绪状态。在run()方法中需要对InterruptedException异常进行处理。在使用Interrupt()方法时需要注意,如果线程处于正常运行状态,调用Interrupt()方法并不会使线程立即退出,而是将线程标记为需要中断,并在有机会退出时退出。使用Interrupt()方法可以中断线程睡眠、等待、输入输出等操作。
// 正常退出
public class MyThread extends Thread {
@Override
public void run() {
// run方法中执行代码
}
}
MyThread myThread = new MyThread();
myThread.start();
// 使用标志变量
public class MyThread extends Thread {
private volatile boolean flag = true;
public void stopThread() {
flag = false;
}
@Override
public void run() {
while (flag) {
// run方法中执行代码
}
}
}
MyThread myThread = new MyThread();
myThread.start();
myThread.stopThread();
// 使用Interrupt()方法
public class MyThread extends Thread {
@Override
public void run() {
try {
while (!isInterrupted()) {
// run方法中执行代码
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
MyThread myThread = new MyThread();
myThread.start();
myThread.interrupt();
### 线程的互斥与同步
多线程程序中,如果多个线程同时访问共享资源,可能会出现数据不一致的情况。在Java多线程编程中,可以使用synchronized关键字对代码块或方法进行加锁,以保证多个线程访问共享资源时的互斥性和同步性。
#### synchronized关键字
synchronized关键字可以用来修饰代码块和方法。当某个线程进入synchronized代码块或方法时,会将锁标记为已占用,其他线程必须等待该线程释放锁后才能进入synchronized代码块或方法。
// 代码块同步
public void subtractOne() {
synchronized (this) {
if (count > 0) {
count--;
}
}
}
// 方法同步
public synchronized void subtractTwo() {
if (count > 0) {
count--;
}
}
#### Lock接口
除了使用synchronized关键字实现线程同步,还可以使用Lock接口及其实现类ReentrantLock来实现线程互斥和同步。Lock提供了比synchronized更多的功能,比如可以设置超时时间、尝试获取锁等。
Lock lock = new ReentrantLock();
lock.lock();
try {
// 需要同步的代码块
} finally {
lock.unlock();
}
### 线程通信
Java提供了wait()、notify()和notifyAll()这三个方法来实现线程通信。这三个方法必须在synchronized代码块中调用,否则会抛出IllegalMonitorStateException异常。
#### wait()方法
wait()方法会使当前线程进入等待状态,直到其他线程调用notify()或notifyAll()方法将其唤醒。在调用wait()方法时,必须持有对象的锁,否则会抛出IllegalMonitorStateException异常。wait()方法会释放持有的锁,以允许其他线程访问同步块。
synchronized (obj) {
while (condition != true) {
obj.wait();
}
// 执行操作
}
#### notify()方法
notify()方法用于唤醒一个等待中的线程,如果有多个线程在等待,则随机唤醒其中一个线程。在调用notify()方法时,必须持有对象的锁,否则会抛出IllegalMonitorStateException异常。
synchronized (obj) {
condition = true;
obj.notify();
}
#### notifyAll()方法
notifyAll()方法用于唤醒所有等待中的线程,每个线程都可以进行竞争执行。在调用notifyAll()方法时,必须持有对象的锁,否则会抛出IllegalMonitorStateException异常。
synchronized (obj) {
condition = true;
obj.notifyAll();
}
### 线程状态控制
Java多线程编程中,可以使用Thread类的一些方法控制线程状态。
#### Thread.sleep()方法
Thread.sleep()方法可以使线程进入睡眠状态,时间到后自动唤醒。在调用sleep()方法时,不需要持有锁,但是可能会抛出InterruptedException异常,需要进行异常处理。
try {
// 线程睡眠100毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
#### Thread.yield()方法
Thread.yield()方法可以使线程放弃当前使用的CPU资源,让其他线程继续执行。调用yield()方法并不会将线程转移到就绪状态,而是仅仅让线程进入可运行状态,等待获取CPU资源。
Thread.yield();
#### Thread.join()方法
Thread.join()方法可以使当前线程等待其他线程执行完毕,再继续执行。在调用join()方法时,需要先将其他线程创建并启动,然后再调用join()方法等待其他线程执行完毕。
`java
Thread threadOne = new Thread(() -> {
// 线程One的代码
});
Thread threadTwo = new Thread(() -> {
// 线程Two的代码
});
threadOne.start();
