在现代软件开发中,多线程编程是一个重要的概念,它能够充分利用多核处理器的能力,提高程序的执行效率。Java 语言内置了对多线程的支持,使得开发者可以方便地创建和管理线程。
创建线程
1. 继承Thread类
这是最直接的方式,通过创建一个继承自Thread类的子类,并重写run()方法来定义线程的行为。之后,创建该子类的实例并调用start()方法来启动线程。
实现步骤:
1. 创建一个继承自Thread类的子类。
2. 重写run()方法,定义线程的执行逻辑。
3. 创建子类的实例。
4. 调用start()方法启动线程。
class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程 " + Thread.currentThread().getName() + " 正在运行");
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 启动线程
}
}
2. 实现Runnable接口
这种方式更为推荐,因为它符合面向接口编程的原则,且不会受到单继承的限制。创建一个实现了 Runnable接口的类,实现run()方法。然后将Runnable实例传递给Thread类的构造器,最后调用Thread对象的start()方法来启动线程。
实现步骤:
1. 创建一个实现Runnable接口的类。
2. 实现run()方法,定义线程的执行逻辑。
3. 创建Runnable接口的实现类的实例。
4. 将Runnable实例传递给Thread类的构造器,创建Thread对象。
5. 调用Thread对象的start()方法启动线程。
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程 " + Thread.currentThread().getName() + " 通过 Runnable 运行");
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable(), "MyRunnableThread");
thread.start(); // 启动线程
}
}
3. 实现Callable接口
与Runnable接口类似,Callable接口也代表了一个任务,但它可以返回结果并且可以抛出异常。Callable接口中的call()方法返回一个结果值,并且可能抛出异常。通常,Callable任务的结果会被Future对象包装起来,通过ExecutorService执行Callable任务。
实现步骤:
1. 创建一个实现Callable接口的类。
2. 实现call()方法,定义线程的执行逻辑,并返回一个结果。
3. 创建Callable接口的实现类的实例。
4. 使用FutureTask包装Callable实例。
5. 将FutureTask实例传递给Thread类的构造器,创建Thread对象。
6. 调用Thread对象的start()方法启动线程。
7. 通过FutureTask的get()方法获取任务的执行结果。
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
}
return sum;
}
public static void main(String[] args) {
MyCallable callable = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask, "MyCallableThread");
thread.start();
try {
Integer result = futureTask.get(); // 获取计算结果
System.out.println("线程 " + Thread.currentThread().getName() + " 计算结果: " + result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
线程的常用方法
1.start()
功能:启动线程,调用线程的run()方法。
示例:
Thread thread = new Thread(() -> {
System.out.println("线程运行中...");
});
thread.start();
2. run()
功能:线程的主体,包含线程要执行的代码。
示例:
class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程 " + Thread.currentThread().getName() + " 正在运行");
}
}
3. join()
功能:等待当前线程终止。可以带一个超时参数,表示等待的时间(以毫秒为单位)。
示例:
Thread thread1 = new Thread(() -> {
try {
Thread.sleep(1000);
System.out.println("线程1运行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread thread2 = new Thread(() -> {
try {
thread1.join(); // 等待 thread1 完成
System.out.println("线程2运行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread1.start();
thread2.start();
4. sleep(long millis)
功能:使当前正在执行的线程暂停指定的时间(以毫秒为单位),进入阻塞状态。
示例:
Thread thread = new Thread(() -> {
try {
System.out.println("线程开始睡眠");
Thread.sleep(2000); // 暂停2秒
System.out.println("线程睡眠结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
5. yield()
功能:让出CPU,允许其他线程执行。不保证当前线程会立即停止执行。
示例:
Thread thread = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("线程运行中...");
if (i == 2) {
Thread.yield(); // 让出CPU
}
}
});
thread.start();
6. isAlive()
功能:判断线程是否还活着(即是否已经完成执行)。
示例:
Thread thread = new Thread(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
while (thread.isAlive()) {
System.out.println("线程还在运行...");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程已结束");
7. interrupt()
功能:中断线程。如果线程处于阻塞状态(如sleep或wait),会抛出InterruptedException。
示例:
Thread thread = new Thread(() -> {
try {
System.out.println("线程开始睡眠");
Thread.sleep(5000); // 暂停5秒
System.out.println("线程睡眠结束");
} catch (InterruptedException e) {
System.out.println("线程被中断");
}
});
thread.start();
try {
Thread.sleep(1000); // 主线程暂停1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt(); // 中断线程
8. getName()和setName(String name)
功能:获取和设置线程的名称。
示例:
Thread thread = new Thread(() -> {
System.out.println("线程名称: " + Thread.currentThread().getName());
}, "MyThread");
thread.start();
9. getId()
功能:获取线程的唯一标识符。
示例:
Thread thread = new Thread(() -> {
System.out.println("线程ID: " + Thread.currentThread().getId());
});
thread.start();
10. getPriority()和setPriority(int priority)
功能:获取和设置线程的优先级。优先级范围是1到10,默认值是5。
示例:
Thread thread = new Thread(() -> {
System.out.println("线程优先级: " + Thread.currentThread().getPriority());
});
thread.setPriority(Thread.MAX_PRIORITY); // 设置最高优先级
thread.start();
11. isDaemon()和setDaemon(boolean on)
功能:获取和设置线程是否为守护线程。守护线程通常用于在后台执行一些服务,如垃圾回收。当所有非守护线程结束后,程序会自动退出。
示例:
Thread thread = new Thread(() -> {
while (true) {
System.out.println("守护线程运行中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.setDaemon(true); // 设置为守护线程
thread.start();
线程安全
在多线程环境中,多个线程可能会同时访问和修改共享资源,这可能导致数据不一致、死锁等问题。线程安全是指当多个线程访问某个类时,不管运行时环境如何调度这些线程,这个类的行为都能正确表现。确保线程安全的方法有很多,包括使用同步机制、不可变对象、原子类等。
线程安全的常见问题
数据竞争:多个线程同时读取和修改同一个变量,导致数据不一致。
死锁:两个或多个线程互相等待对方释放资源,导致所有线程都无法继续执行。
活锁:线程不断重复相同的操作,无法向前推进。
饥饿:某些线程因为长时间无法获得必要的资源而无法执行。
确保线程安全的方法
1. 同步机制
synchronized关键字
方法同步:在方法声明前加上synchronized关键字,确保同一时刻只有一个线程可以执行该方法。
代码块同步:在代码块前加上synchronized关键字,并指定一个对象作为锁,确保同一时刻只有一个线程可以执行该代码块。示例代码:
public class Counter {
private int count = 0;
// 方法同步
public synchronized void increment() {
count++;
}
// 代码块同步
public void incrementWithBlock() {
synchronized (this) {
count++;
}
}
public int getCount() {
return count;
}
}
public class Main {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("最终计数: " + counter.getCount());
}
}
ReentrantLock
提供了比synchronized更灵活的锁定操作,支持公平锁、非公平锁等。
需要手动获取和释放锁。示例代码:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private int count = 0;
private final Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
return count;
}
}
public class Main {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("最终计数: " + counter.getCount());
}
}
2. 不可变对象
不可变对象一旦创建后,其状态就不能改变。
常见的不可变对象有String、Integer等。示例代码:
public final class ImmutableClass {
private final int value;
public ImmutableClass(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
public class Main {
public static void main(String[] args) {
ImmutableClass obj = new ImmutableClass(10);
Thread t1 = new Thread(() -> {
System.out.println("线程1读取值: " + obj.getValue());
});
Thread t2 = new Thread(() -> {
System.out.println("线程2读取值: " + obj.getValue());
});
t1.start();
t2.start();
}
}
3. 原子类
java.util.concurrent.atomic包提供了一些原子操作类,如AtomicInteger、AtomicLong等。
这些类提供了原子性的操作,确保在多线程环境下不会出现数据竞争。示例代码:
import java.util.concurrent.atomic.AtomicInteger;
public class Counter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
public int getCount() {
return count.get();
}
}
public class Main {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("最终计数: " + counter.getCount());
}
}
标签:Java,thread,Thread,编程,start,线程,new,多线程,public
From: https://blog.csdn.net/b123321888/article/details/142767910