📜  Java中的线程间通信(1)

📅  最后修改于: 2023-12-03 15:02:03.193000             🧑  作者: Mango

Java中的线程间通信

在Java中,线程间通信是多线程编程中的一个重要概念。当多个线程并发执行时,可能会需要线程间通信来实现线程间的同步和协作。

Java提供了多种机制来实现线程间通信,主要包括:

  • 互斥锁
  • 条件变量
  • 管道
  • 信号量
  • 读写锁
  • 同步队列
  • 等待通知机制
互斥锁

互斥锁是最基本的线程同步机制。在Java中,可以使用synchronized关键字来实现互斥锁。

使用synchronized关键字的时候,需要指定一个共享对象,称为“锁对象”。在临界区代码执行时,线程会尝试获取锁对象的锁,若锁已被其他线程占用,则会被阻塞等待,直到锁被释放。

示例代码:

public class MyThread extends Thread {
    private Object lock;
 
    public MyThread(Object lock) {
        this.lock = lock;
    }
 
    @Override
    public void run() {
        synchronized (lock) {
            // 这里是临界区
            // ...
        }
    }
}
条件变量

条件变量是一种用于线程间通信的机制。在Java中,可以使用wait()notify()方法来实现条件变量。

当一个线程调用了wait()方法之后,它会释放当前持有的锁对象,并且进入等待状态,直到其他线程调用了相同锁对象的notify()notifyAll()方法,唤醒等待线程。

示例代码:

public class MyThread extends Thread {
    private Object lock;
 
    public MyThread(Object lock) {
        this.lock = lock;
    }
 
    @Override
    public void run() {
        synchronized (lock) {
            try {
                lock.wait();
                // 线程被唤醒后,执行这里的代码
                // ...
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
管道

管道是一种用于进程间通信的机制,Java中的管道可以实现线程间通信。管道由两个管道流组成,一个用于输入,一个用于输出。

示例代码:

public class MyThread1 extends Thread {
    private PipedOutputStream outputStream;
 
    public MyThread1(PipedOutputStream outputStream) {
        this.outputStream = outputStream;
    }
 
    @Override
    public void run() {
        try {
            outputStream.write("Hello, world".getBytes());
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
public class MyThread2 extends Thread {
    private PipedInputStream inputStream;
 
    public MyThread2(PipedInputStream inputStream) {
        this.inputStream = inputStream;
    }
 
    @Override
    public void run() {
        try {
            byte[] buffer = new byte[1024];
            int len = inputStream.read(buffer);
            System.out.println(new String(buffer, 0, len));
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
public class Test {
    public static void main(String[] args) {
        try {
            PipedOutputStream outputStream = new PipedOutputStream();
            PipedInputStream inputStream = new PipedInputStream(outputStream);
            MyThread1 thread1 = new MyThread1(outputStream);
            MyThread2 thread2 = new MyThread2(inputStream);
            thread1.start();
            thread2.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
信号量

信号量是一种用于控制资源访问权限的机制。在Java中,可以使用Semaphore类来实现信号量。

Semaphore类提供了两个方法:acquire()release()。当一个线程调用acquire()方法时,它会尝试获取信号量,如果当前有可用资源,则会获取成功。如果没有可用资源,则会被阻塞等待,直到其他线程释放资源。当一个线程调用release()方法时,它会释放一个资源,并唤醒一个正在等待资源的线程。

示例代码:

public class MyThread extends Thread {
    private Semaphore semaphore;
 
    public MyThread(Semaphore semaphore) {
        this.semaphore = semaphore;
    }
 
    @Override
    public void run() {
        try {
            semaphore.acquire();
            // 在这里执行临界区代码
            // ...
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
读写锁

读写锁是一种特殊的锁,适用于读操作远远多于写操作的情况。在Java中,可以使用ReentrantReadWriteLock类来实现读写锁。

ReentrantReadWriteLock类提供了两个锁对象:读锁和写锁。当一个线程获取读锁时,如果当前没有写锁,那么它可以获取读锁并继续执行。当多个线程同时获取读锁时,它们可以同时执行,不会互相影响。当一个线程获取写锁时,它必须等待所有读锁释放完毕,并且当前没有其他线程持有写锁,才能获取写锁并继续执行。

示例代码:

public class MyThread extends Thread {
    private ReentrantReadWriteLock lock;
 
    public MyThread(ReentrantReadWriteLock lock) {
        this.lock = lock;
    }
 
    @Override
    public void run() {
        lock.readLock().lock();
        // 在这里执行读操作
        lock.readLock().unlock();
 
        lock.writeLock().lock();
        // 在这里执行写操作
        lock.writeLock().unlock();
    }
}
同步队列

同步队列是一种用于线程间通信的机制。在Java中,可以使用SynchronousQueue类来实现同步队列。

SynchronousQueue类是一个没有容量的队列。当一个线程尝试向队列中添加元素时,如果当前没有其他线程正在等待获取元素,并且没有其他元素在队列中等待,那么该线程会被阻塞等待,直到另一个线程尝试从队列中获取元素。当一个线程尝试从队列中获取元素时,如果当前没有其他线程正在等待添加元素,并且有元素在队列中等待获取,那么该线程会获取到该元素并继续执行。

示例代码:

public class MyThread1 extends Thread {
    private SynchronousQueue<Integer> queue;
 
    public MyThread1(SynchronousQueue<Integer> queue) {
        this.queue = queue;
    }
 
    @Override
    public void run() {
        try {
            queue.put(123);
            // 将123添加到队列中,会被阻塞等待
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
 
public class MyThread2 extends Thread {
    private SynchronousQueue<Integer> queue;
 
    public MyThread2(SynchronousQueue<Integer> queue) {
        this.queue = queue;
    }
 
    @Override
    public void run() {
        try {
            Integer result = queue.take();
            // 从队列中获取元素,如果没有元素在队列中等待,则会被阻塞等待
            System.out.println(result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
 
public class Test {
    public static void main(String[] args) {
        SynchronousQueue<Integer> queue = new SynchronousQueue<>();
        MyThread1 thread1 = new MyThread1(queue);
        MyThread2 thread2 = new MyThread2(queue);
        thread1.start();
        thread2.start();
    }
}
等待通知机制

等待通知机制是一种用于线程间通信的机制。在Java中,可以使用wait()notify()方法来实现等待通知机制。

当一个线程调用了wait()方法之后,它会释放当前持有的锁对象,并且进入等待状态,直到其他线程调用了相同锁对象的notify()notifyAll()方法,唤醒等待线程。当一个线程调用了notify()方法时,它会唤醒一个正在等待这个锁对象的线程,并且释放锁对象。

示例代码:

public class MyThread extends Thread {
    private Object lock;
 
    public MyThread(Object lock) {
        this.lock = lock;
    }
 
    @Override
    public void run() {
        synchronized (lock) {
            try {
                lock.wait();
                // 线程被唤醒后,执行这里的代码
                // ...
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
 
public class Test {
    public static void main(String[] args) {
        Object lock = new Object();
        MyThread thread = new MyThread(lock);
        thread.start();
 
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 
        synchronized (lock) {
            lock.notify();
        }
    }
}

以上是Java中的线程间通信的介绍,提供了多种实现方式,可以根据具体的业务需求来选用合适的机制。