Java多线程 同步互斥

引言

在计算机科学中,多线程是一种使用多个线程执行多个任务的技术。在Java中,多线程编程是非常常见的。然而,当多个线程同时访问共享资源时,可能会出现数据不一致的问题。为了解决这个问题,Java提供了同步和互斥机制。

本文将介绍Java中的多线程编程以及如何使用同步和互斥机制来确保线程安全。

多线程编程基础

多线程编程允许应用程序同时执行多个任务。每个任务在独立的线程中运行,这些线程可以并行执行。

Java中的多线程编程主要依赖于Thread类和Runnable接口。下面是一个简单的示例,展示了如何创建和运行线程:

public class MyThread extends Thread {
    public void run() {
        System.out.println("Hello from MyThread!");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println("Hello from Main!");
    }
}

上述代码中,MyThread类继承自Thread类,并重写了run方法。在main方法中,我们创建了一个MyThread实例,并调用了start方法来启动线程。start方法将会自动调用run方法。

在运行上述代码时,可能会出现两种输出情况,因为MyThreadmain方法是并行执行的。

线程同步

当多个线程同时访问共享资源时,可能会导致数据不一致的问题,这种情况称为竞态条件。为了避免竞态条件,我们可以使用线程同步机制。

同步方法

Java中,可以使用synchronized关键字将方法声明为同步方法。当一个线程调用同步方法时,其他线程将被阻塞,直到该方法执行完毕。

下面是一个使用同步方法的示例:

public class Counter {
    private int count = 0;
    
    public synchronized void increment() {
        count++;
    }
    
    public synchronized int getCount() {
        return count;
    }
}

public class MyThread extends Thread {
    private Counter counter;
    
    public MyThread(Counter counter) {
        this.counter = counter;
    }
    
    public void run() {
        for (int i = 0; i < 1000; i++) {
            counter.increment();
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Counter counter = new Counter();
        
        MyThread thread1 = new MyThread(counter);
        MyThread thread2 = new MyThread(counter);
        
        thread1.start();
        thread2.start();
        
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("Count: " + counter.getCount());
    }
}

上述代码中,Counter类有一个count变量和两个同步方法incrementgetCount。在increment方法中,我们使用synchronized关键字修饰,以确保只有一个线程可以同时访问该方法。

main方法中,我们创建了两个MyThread实例,并传递了同一个Counter实例。每个线程将会调用increment方法1000次,然后通过getCount方法获取计数器的值。

由于increment方法是同步的,两个线程不会同时访问该方法,从而避免了数据不一致的问题。

同步代码块

除了同步方法,还可以使用同步代码块来实现线程同步。同步代码块使用synchronized关键字,将一部分代码包裹起来,只有一个线程可以同时执行该代码块。

下面是一个使用同步代码块的示例:

public class Counter {
    private int count = 0;
    
    public void increment() {
        synchronized(this) {
            count++;
        }
    }
    
    public int getCount() {
        synchronized(this) {
            return count;
        }
    }
}

上述代码中,我们在incrementgetCount方法内