欢迎访问宙启技术站
智能推送

Java多线程编程函数库大全:线程、锁和同步的使用技巧

发布时间:2023-06-06 15:27:53

Java是一门面向对象的编程语言,同时具有丰富的多线程编程函数库。在Java中,使用线程、锁和同步是非常容易的。本文将介绍Java中常用的多线程编程函数库,包括线程、锁和同步的使用技巧。

1. 线程

在Java中,线程是一个可并发执行的代码片段。线程分为两种:用户线程和守护线程。用户线程指的是由用户创建的线程,程序会等待所有用户线程执行完成后再退出。守护线程不是程序中止的条件,当所有用户线程结束后,Java虚拟机会退出。

Java中创建线程的方法有两种:继承Thread类和实现Runnable接口。下面分别介绍这两种方法的使用。

1.1 继承Thread类

继承Thread类的方式是一种比较常见的创建线程的方法。在这种方法中,首先需要创建一个继承自Thread类的新类,然后覆盖Thread类中的run()方法。在run()方法中写自己想要线程执行的代码,最后创建该新类的实例并调用start()方法来启动该线程。

下面是一个例子:

public class MyThread extends Thread {

    @Override

    public void run() {

        System.out.println("MyThread running");

    }

}

public class Main {

    public static void main(String[] args) {

        MyThread thread = new MyThread();

        thread.start();

    }

}

1.2 实现Runnable接口

实现Runnable接口是另一种创建线程的常见方法。在这种方法中,需要创建一个类并实现Runnable接口。在该类中,实现Runnable接口的run()方法,并在run()方法中写自己想要线程执行的代码。最后,创建该类的实例,并将其作为参数传递给Thread类的构造函数。最后调用Thread类的start()方法启动该线程。

下面是一个例子:

public class MyRunnable implements Runnable {

    @Override

    public void run() {

        System.out.println("MyRunnable running");

    }

}

public class Main {

    public static void main(String[] args) {

        MyRunnable runnable = new MyRunnable();

        Thread thread = new Thread(runnable);

        thread.start();

    }

}

2. 锁

Java中的锁是用于线程同步的一种机制。使用锁可以避免多个线程同时执行同一段代码。Java中有两种锁:synchronized锁和ReentrantLock。

2.1 synchronized锁

synchronized锁是Java内置的一种锁机制。在Java中,可以使用synchronized关键字指定一个代码块或一个方法进行同步。synchronized关键字会锁定当前对象,如果多个线程试图同时访问同一段代码或方法,只有一个线程会获得锁定,并执行该段代码或方法,而其他线程则会等待。

下面是一个例子:

public class Main {

    private final Object lock = new Object();

    public synchronized void synchronizedMethod() throws InterruptedException {

        System.out.println(Thread.currentThread().getName() + " running");

        Thread.sleep(1000);

    }

    public void nonSynchronizedMethod() {

        System.out.println(Thread.currentThread().getName() + " running");

    }

    public static void main(String[] args) throws InterruptedException {

        Main main = new Main();

        Thread thread1 = new Thread(() -> {

            try {

                main.synchronizedMethod();

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        });

        Thread thread2 = new Thread(() -> main.nonSynchronizedMethod());

        thread1.start();

        thread2.start();

        thread1.join();

        thread2.join();

    }

}

在上面的例子中,synchronizedMethod()方法使用synchronized关键字锁定this对象,同时nonSynchronizedMethod()方法没有被同步。可以看到,synchronizedMethod()方法只会被一个线程访问,而nonSynchronizedMethod()方法则可以被多个线程同时访问。

2.2 ReentrantLock

ReentrantLock是Java提供的另一种锁机制。与synchronized锁不同,ReentrantLock可以显式地获取和释放锁。在使用ReentrantLock进行同步时,需要显式地获取锁,执行完成后再显式地释放锁。与synchronized锁相比,ReentrantLock的灵活性更高,但使用起来也更加复杂。

下面是一个例子:

public class Main {

    private final ReentrantLock lock = new ReentrantLock();

    public void syncMethod() {

        lock.lock();

        try {

            System.out.println(Thread.currentThread().getName() + " running");

            Thread.sleep(1000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        } finally {

            lock.unlock();

        }

    }

    public void nonSyncMethod() {

        System.out.println(Thread.currentThread().getName() + " running");

    }

    public static void main(String[] args) throws InterruptedException {

        Main main = new Main();

        Thread thread1 = new Thread(() -> main.syncMethod());

        Thread thread2 = new Thread(() -> main.nonSyncMethod());

        thread1.start();

        thread2.start();

        thread1.join();

        thread2.join();

    }

}

在上面的例子中,syncMethod()方法使用ReentrantLock显式获取锁,并在方法执行结束后释放锁。可以看到,只有一个线程可以访问syncMethod()方法,而nonSyncMethod()方法可以被多个线程同时访问。

3. 同步

在多线程编程中,为了保证线程安全和数据的一致性,需要使用同步机制。Java中同步机制的实现一般使用synchronized关键字。

3.1 synchronized方法

如上所述,在Java中,可以使用synchronized关键字指定一个方法进行同步。在synchronized方法运行时,Java会自动获取或释放与方法所属对象关联的锁。因此,synchronized方法只能被一个线程执行,直到该方法执行完毕并释放锁才能被其他线程执行。

下面是一个例子:

public class MyRunnable {

    private int count;

    public synchronized void incrementCount() throws InterruptedException {

        Thread.sleep(1000);

        count++;

    }

    public int getCount() {

        return count;

    }

}

在上面的例子中,incrementCount()方法使用synchronized关键字进行同步,因此只有一个线程可以访问该方法。相比于使用synchronized代码块进行同步,使用synchronized方法更加简便。

3.2 synchronized代码块

与synchronized方法相比,synchronized代码块可以对代码的范围进行更加细致的控制。在synchronized代码块中,需要指定一个对象作为锁。在代码块中执行时,Java会获取该对象的锁,并在代码块执行结束后释放锁。因此,synchronized代码块可以避免多个线程同时访问同一段代码。

下面是一个例子:

public class MyRunnable {

    private int count;

    private final Object lock = new Object();

    public void incrementCount() throws InterruptedException {

        synchronized (lock) {

            Thread.sleep(1000);

            count++;

        }

    }

    public int getCount() {

        return count;

    }

}

在上面的例子中,使用synchronized代码块锁定lock对象,从而保证只有一个线程可以访问代码块中的内容。需要注意的是,在使用synchronized代码块时,需要确保锁定的对象在线程之间是可见的。

总结

本文介绍了Java中常用的多线程编程函数库,包括线程、锁和同步的使用技巧。在实际使用中,需要根据具体的场景和需求选择适当的函数库和技巧,以确保代码的正确性和性能。