java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java线程阻塞和唤醒

Java线程阻塞和唤醒的几种方式详解

作者:Ramscy

这篇文章主要介绍了Java线程阻塞和唤醒的几种方式详解,线程阻塞是指当一个线程无法继续执行时,它会进入阻塞状态,直到某个条件满足后才能继续执行,线程阻塞可以通过多种方式实现,如等待锁、等待IO操作、等待其他线程的完成等,需要的朋友可以参考下

Object类自带的方法

使用wait()方法来阻塞线程,使用notify()和notifyAll()方法来唤醒线程。 调用wait()方法后,线程将被阻塞,wait()方法将会释放当前持有的监视器锁(monitor),直到有线程调用notify/notifyAll()方法后方能继续执行。 notify/notifyAll()方法只是解除了等待线程的阻塞,并不会马上释放监视器锁,而是在相应的被synchronized关键字修饰的同步方法或同步代码块执行结束后才自动释放锁。 默认使用非公平锁,无法修改。

缺点:

public class SynchronizedDemo {

// 三个线程交替打印ABC
    public static void main(String[] args) {

        Print print = new Print();

        new Thread(() -> {
            while (true) {
                print.printA();
            }
        }, "A").start();
        new Thread(() -> {
            while (true) {
                print.printB();
            }
        }, "B").start();
        new Thread(() -> {
            while (true) {
                print.printC();
            }
        }, "C").start();
    }
}

class Print {

    Object object = new Object();
    int num = 1;

    public void printA() {
        synchronized (object) {
            try {
                while (num != 1) {
                    object.wait();
                }
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName() + "==>A");
                }
                num = 2;
                object.notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void printB() {
        synchronized (object) {
            try {
                while (num != 2) {
                    object.wait();
                }
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + "==>B");
                }
                num = 3;
                object.notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void printC() {
        synchronized (object) {
            try {
                while (num != 3) {
                    object.wait();
                }
                for (int i = 0; i < 15; i++) {
                    System.out.println(Thread.currentThread().getName() + "==>C");
                }
                num = 1;
                object.notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Condition接口

使用await()方法来阻塞线程,signal()/singnalAll()方法来唤醒线程。

需要使用lock对象的newCondition()方法获得Condition条件对象(可有多个)。

可实现公平锁,默认是非公平锁

缺点:

public class ConditionDemo {

// 三个线程交替打印ABC
    public static void main(String[] args) {
        Print print = new Print();
        new Thread(() -> {
            while (true) {
                print.printA();
            }
        }, "A").start();

        new Thread(() -> {
            while (true) {
                print.printB();
            }
        }, "B").start();

        new Thread(() -> {
            while (true) {
                print.printC();
            }
        }, "C").start();
    }
}

class Print {

    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private int num = 1;

    public void printA() {

        lock.lock();
        try {
            while (num != 1) {
                condition1.await();
            }
            for (int i = 0; i < 5; ++i) {
                System.out.println(Thread.currentThread().getName() + "==>A");
            }
            num = 2;
            condition2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printB() {

        lock.lock();
        try {
            while (num != 2) {
                condition2.await();
            }
            for (int i = 0; i < 10; ++i) {
                System.out.println(Thread.currentThread().getName() + "==>B");
            }
            num = 3;
            condition3.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printC() {

        lock.lock();
        try {
            while (num != 3) {
                condition3.await();
            }
            for (int i = 0; i < 15; ++i) {
                System.out.println(Thread.currentThread().getName() + "==>C");
            }
            num = 1;
            condition1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

LockSupport

使用park()来阻塞线程,用unpark()方法来唤醒线程。 这里有一个许可证的概念,许可不能累积,并且最多只能有一个许可,只有1和0的区别。

特点:

public class LockSupportDemo {

// 三个线程交替打印ABC
    public static void main(String[] args) throws Exception {

        Print print = new Print();

        Thread threadA = new Thread(() -> {
            while (true) {
                print.printA();
            }
        }, "A");

        Thread threadB = new Thread(() -> {
            while (true) {
                print.printB();
            }
        }, "B");

        Thread threadC = new Thread(() -> {
            while (true) {
                print.printC();
            }
        }, "C");

        threadA.start();
        threadB.start();
        threadC.start();

        while (true) {
            LockSupport.unpark(threadA);
            LockSupport.unpark(threadB);
            LockSupport.unpark(threadC);
        }

    }
}

class Print {

    private int num = 1;

    public void printA() {
        while (num != 1) {
            LockSupport.park();
        }
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "==>A");
        }
        num = 2;
    }

    public void printB() {
        while (num != 2) {
            LockSupport.park();
        }
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "==>B");
        }
        num = 3;
    }

    public void printC() {
        while (num != 3) {
            LockSupport.park();
        }
        for (int i = 0; i < 15; i++) {
            System.out.println(Thread.currentThread().getName() + "==>C");
        }
        num = 1;
    }
}

到此这篇关于Java线程阻塞和唤醒的几种方式详解的文章就介绍到这了,更多相关Java线程阻塞和唤醒内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文