您好,欢迎来到易榕旅网。
搜索
您的当前位置:首页正文

Java 多线程:线程状态 & 线程操作 & 线程同步

来源:易榕旅网

Java 多线程是指通过同时运行多个线程来提高程序的并发性和性能。在 Java 中,线程是并发执行的基本单位,每个线程都有自己独立的执行路径。了解线程的生命周期、线程操作及线程同步的机制对于高效编写并发程序至关重要。

本篇将深入讲解 Java 多线程的三个核心主题:线程状态、线程操作和线程同步,并通过代码示例进行讲解。

1. 线程状态

Java 中的线程有六种状态,每个状态表示线程在不同执行阶段的状态。线程状态的转化由 Java 虚拟机(JVM)和操作系统共同管理。

1.1 线程的六种状态

1.2 线程状态转化图

   +--------------------+
   |      New           |
   +--------------------+
           |
           v
   +--------------------+        start()
   |     Runnable       | <-----------------+
   +--------------------+                   |
           |                                 |
           v                                 |
   +--------------------+        run()      |
   |     Running        | -------------------+
   +--------------------+ 
           |
           v
   +--------------------+
   |     Blocked        |
   +--------------------+
           |
           v
   +--------------------+   wait(), join(), sleep()
   |      Waiting       |
   +--------------------+
           |
           v
   +--------------------+
   |   Timed Waiting    |
   +--------------------+
           |
           v
   +--------------------+
   |     Terminated     |
   +--------------------+

2. 线程操作

线程的生命周期控制是通过线程操作来实现的。在 Java 中,我们可以使用 Thread 类或实现 Runnable 接口来创建线程。Java 提供了一些常用的线程操作,如启动线程、等待线程、暂停线程等。

2.1 创建线程

2.1.1 继承 Thread 类

通过继承 Thread 类并重写其 run() 方法来实现自定义线程行为。

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread is running...");
    }

    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();  // 启动线程
    }
}
2.1.2 实现 Runnable 接口

实现 Runnable 接口并将其传递给 Thread 对象来创建线程。这种方式更灵活,适合线程池使用。

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Runnable thread is running...");
    }

    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();  // 启动线程
    }
}

2.2 线程的常用操作

  • start():启动线程,调用该方法会将线程从新建状态转变为就绪状态。
  • sleep(long millis):使当前线程休眠指定的时间,在休眠期间不会占用 CPU 资源。
  • join():等待当前线程执行完毕,通常用于一个线程等待另一个线程结束后继续执行。
  • yield():让出 CPU 使用权,当前线程会进入就绪状态,可能会被其他线程抢占。
  • interrupt():中断线程的执行,通常用于停止线程的工作。
  • setPriority(int priority):设置线程的优先级,优先级的值范围是 1-10,默认是 5。

2.3 代码示例:线程操作

class MyThread extends Thread {
    @Override
    public void run() {
        try {
            System.out.println("Thread is going to sleep...");
            Thread.sleep(2000);
            System.out.println("Thread is awake...");
        } catch (InterruptedException e) {
            System.out.println("Thread was interrupted!");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread thread = new MyThread();
        thread.start();  // 启动线程
        thread.join();   // 等待线程执行完毕
        System.out.println("Main thread finished");
    }
}

3. 线程同步

在多线程环境下,多个线程同时操作共享资源可能会引发并发问题,如数据的不一致性、脏数据等。为了避免这些问题,Java 提供了多种线程同步机制,确保共享资源的安全访问。

3.1 同步的关键字

  • synchronized:用于修饰方法或代码块,确保同一时间只有一个线程能够访问被修饰的代码块或方法。
3.1.1 同步方法
class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

public class TestSync {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println("Count: " + counter.getCount());  // 输出: 2000
    }
}
3.1.2 同步代码块
class Counter {
    private int count = 0;

    public void increment() {
        synchronized (this) {  // 锁定当前对象
            count++;
        }
    }

    public int getCount() {
        return count;
    }
}

public class TestSync {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println("Count: " + counter.getCount());  // 输出: 2000
    }
}

3.2 死锁

死锁是指两个或多个线程在执行过程中因为争夺资源而造成一种相互等待的现象,从而导致程序无法继续执行。避免死锁的常见方法包括:

  • 避免嵌套锁:避免多个线程持有多个锁。
  • 锁定顺序:在多个线程需要获取多个锁时,按照固定顺序获取锁,防止死锁发生。
  • 使用 tryLock:尝试获取锁,如果不能立即获得锁则返回,避免死锁。

3.3 使用 ReentrantLock

除了 synchronized,Java 还提供了更高级的线程同步机制:ReentrantLock。它比 synchronized 提供了更多的功能,比如尝试获取锁、超时获取锁等。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Counter {
    private int count = 0;
    private Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        return count;
    }
}

public class TestLock {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println("Count: " + counter.getCount());  // 输出: 2000
    }
}

4. 总结

  1. 线程状态:Java 中线程有六种状态,包括新建

、就绪、运行、阻塞、等待、超时等待和终止。了解线程状态有助于理解线程的生命周期及其转化。
2. 线程操作:Java 提供了 Thread 类和 Runnable 接口来创建线程,并通过 start()sleep()join() 等方法进行线程控制。
3. 线程同步:为了避免线程安全问题,Java 提供了 synchronized 关键字和 ReentrantLock 等机制来确保多线程环境下的共享资源安全。

通过合理的线程管理与同步机制,我们可以实现高效且安全的并发程序。

因篇幅问题不能全部显示,请点此查看更多更全内容

Top