Rumah  >  Artikel  >  Java  >  Bagaimana untuk menyelesaikan masalah apabila menggunakan kunci mengundi di Jawa?

Bagaimana untuk menyelesaikan masalah apabila menggunakan kunci mengundi di Jawa?

WBOY
WBOYke hadapan
2023-05-09 17:10:081268semak imbas

Demonstrasi Masalah

Apabila kami tidak menggunakan kunci pengundian, masalah ini mungkin berlaku:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class DeadLockByReentrantLock {
    public static void main(String[] args) {
        Lock lockA = new ReentrantLock(); // 创建锁 A
        Lock lockB = new ReentrantLock(); // 创建锁 B

        // 创建线程 1
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockA.lock(); // 加锁
                System.out.println("线程 1:获取到锁 A!");
                try {
                    Thread.sleep(1000);
                    System.out.println("线程 1:等待获取 B...");
                    lockB.lock(); // 加锁
                    try {
                        System.out.println("线程 1:获取到锁 B!");
                    } finally {
                        lockA.unlock(); // 释放锁
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lockA.unlock(); // 释放锁
                }
            }
        });
        t1.start(); // 运行线程

        // 创建线程 2
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockB.lock(); // 加锁
                System.out.println("线程 2:获取到锁 B!");
                try {
                    Thread.sleep(1000);
                    System.out.println("线程 2:等待获取 A...");
                    lockA.lock(); // 加锁
                    try {
                        System.out.println("线程 2:获取到锁 A!");
                    } finally {
                        lockA.unlock(); // 释放锁
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lockB.unlock(); // 释放锁
                }
            }
        });
        t2.start(); // 运行线程
    }
}

Hasil pelaksanaan kod di atas adalah seperti berikut :

Bagaimana untuk menyelesaikan masalah apabila menggunakan kunci mengundi di Jawa?

Seperti yang dapat dilihat daripada keputusan di atas, pada masa ini dalam program ini, benang sedang menunggu antara satu sama lain dan cuba mendapatkan satu sama lain (kunci) sumber. Ini adalah situasi biasa.

Versi ringkas kunci pengundian

Apabila masalah kebuntuan berlaku, kami boleh menggunakan kunci pengundian untuk menyelesaikannya Idea pelaksanaannya adalah untuk mendapatkan berbilang Kunci, jika sebarang pemerolehan kunci gagal semasa proses. operasi pemulangan dilakukan, semua kunci yang dimiliki oleh utas semasa dilepaskan, dan menunggu pelaksanaan semula seterusnya Ini boleh mengelakkan berbilang utas daripada memiliki dan menduduki sumber kunci pada masa yang sama, dengan itu menyelesaikan masalah secara langsung masalah kebuntuan, versi ringkas kunci mengundi dilaksanakan seperti berikut:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SolveDeadLockExample2 {
    public static void main(String[] args) {
        Lock lockA = new ReentrantLock(); // 创建锁 A
        Lock lockB = new ReentrantLock(); // 创建锁 B

        // 创建线程 1(使用轮询锁)
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 调用轮询锁
                pollingLock(lockA, lockB);
            }
        });
        t1.start(); // 运行线程

        // 创建线程 2
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockB.lock(); // 加锁
                System.out.println("线程 2:获取到锁 B!");
                try {
                    Thread.sleep(1000);
                    System.out.println("线程 2:等待获取 A...");
                    lockA.lock(); // 加锁
                    try {
                        System.out.println("线程 2:获取到锁 A!");
                    } finally {
                        lockA.unlock(); // 释放锁
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lockB.unlock(); // 释放锁
                }
            }
        });
        t2.start(); // 运行线程
    }

    /**
     * 轮询锁
     */
    private static void pollingLock(Lock lockA, Lock lockB) {
        // 轮询锁
        while (true) {
            if (lockA.tryLock()) { // 尝试获取锁
                System.out.println("线程 1:获取到锁 A!");
                try {
                    Thread.sleep(1000);
                    System.out.println("线程 1:等待获取 B...");
                    if (lockB.tryLock()) { // 尝试获取锁
                        try {
                            System.out.println("线程 1:获取到锁 B!");
                        } finally {
                            lockB.unlock(); // 释放锁
                            System.out.println("线程 1:释放锁 B.");
                            break;
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lockA.unlock(); // 释放锁
                    System.out.println("线程 1:释放锁 A.");
                }
            }
            // 等待一秒再继续执行
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Hasil pelaksanaan kod di atas adalah seperti berikut:

Bagaimana untuk menyelesaikan masalah apabila menggunakan kunci mengundi di Jawa?

Seperti yang dapat dilihat daripada keputusan di atas, apabila kita menggunakan kunci mengundi dalam program, masalah kebuntuan tidak akan berlaku, tetapi kunci mengundi di atas tidak sempurna Mari kita lihat ini jenis masalah akan berlaku dengan kunci mengundi?

Masalah 1: Gelung tak terhingga

Untuk versi mudah kunci pengundian di atas, jika benang terus menduduki sumber kunci atau menduduki sumber kunci untuk masa yang lama, ia akan menyebabkan kunci undian untuk masuk Dalam keadaan gelung tak terhingga, ia akan cuba untuk terus memperoleh sumber kunci, yang akan menyebabkan masalah baharu dan overhed prestasi yang tidak perlu Contoh khusus adalah seperti berikut.

Contoh balas

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SolveDeadLockExample {
    public static void main(String[] args) {
        Lock lockA = new ReentrantLock(); // 创建锁 A
        Lock lockB = new ReentrantLock(); // 创建锁 B

        // 创建线程 1(使用轮询锁)
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 调用轮询锁
                pollingLock(lockA, lockB);
            }
        });
        t1.start(); // 运行线程

        // 创建线程 2
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockB.lock(); // 加锁
                System.out.println("线程 2:获取到锁 B!");
                try {
                    Thread.sleep(1000);
                    System.out.println("线程 2:等待获取 A...");
                    lockA.lock(); // 加锁
                    try {
                        System.out.println("线程 2:获取到锁 A!");
                    } finally {
                        lockA.unlock(); // 释放锁
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 如果此处代码未执行,线程 2 一直未释放锁资源
                    // lockB.unlock(); 
                }
            }
        });
        t2.start(); // 运行线程
    }

    /**
     * 轮询锁
     */
    public static void pollingLock(Lock lockA, Lock lockB) {
        while (true) {
            if (lockA.tryLock()) { // 尝试获取锁
                System.out.println("线程 1:获取到锁 A!");
                try {
                    Thread.sleep(1000);
                    System.out.println("线程 1:等待获取 B...");
                    if (lockB.tryLock()) { // 尝试获取锁
                        try {
                            System.out.println("线程 1:获取到锁 B!");
                        } finally {
                            lockB.unlock(); // 释放锁
                            System.out.println("线程 1:释放锁 B.");
                            break;
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lockA.unlock(); // 释放锁
                    System.out.println("线程 1:释放锁 A.");
                }
            }
            // 等待一秒再继续执行
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Keputusan pelaksanaan kod di atas adalah seperti berikut:

Bagaimana untuk menyelesaikan masalah apabila menggunakan kunci mengundi di Jawa?

Seperti yang dapat dilihat daripada keputusan di atas, benang 1 Kunci pengundian memasuki keadaan gelung tak terhingga.

Versi dioptimumkan

Memandangkan situasi gelung tak terhingga di atas, kami boleh menambah baik dua idea berikut:

  • Tambah bilangan maksimum had masa: Jika kunci belum diperoleh selepas n percubaan untuk memperoleh kunci, ia dianggap bahawa pemerolehan kunci gagal, dan pengundian ditamatkan selepas strategi kegagalan dilaksanakan (the strategi kegagalan boleh menjadi pembalakan atau operasi lain) ;

  • Tambah had tempoh maksimum: Jika kunci belum diperoleh selepas n saat cuba mendapatkan kunci , ia akan dianggap bahawa pemerolehan kunci gagal, dan selepas strategi kegagalan dilaksanakan Tamatkan pengundian.

Mana-mana satu daripada strategi di atas boleh menyelesaikan masalah gelung tak terhingga Demi kos pelaksanaan, kami boleh menambah baik kunci pengundian dengan mengundi bilangan kali maksimum,

Kod pelaksanaan khusus adalah seperti berikut:

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

public class SolveDeadLockExample {

    public static void main(String[] args) {
        Lock lockA = new ReentrantLock(); // 创建锁 A
        Lock lockB = new ReentrantLock(); // 创建锁 B

        // 创建线程 1(使用轮询锁)
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 调用轮询锁
                pollingLock(lockA, lockB, 3);
            }
        });
        t1.start(); // 运行线程

        // 创建线程 2
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockB.lock(); // 加锁
                System.out.println("线程 2:获取到锁 B!");
                try {
                    Thread.sleep(1000);
                    System.out.println("线程 2:等待获取 A...");
                    lockA.lock(); // 加锁
                    try {
                        System.out.println("线程 2:获取到锁 A!");
                    } finally {
                        lockA.unlock(); // 释放锁
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 线程 2 忘记释放锁资源
                    // lockB.unlock(); // 释放锁
                }
            }
        });
        t2.start(); // 运行线程
    }

    /**
     * 轮询锁
     *
     * maxCount:最大轮询次数
     */
    public static void pollingLock(Lock lockA, Lock lockB, int maxCount) {
        // 轮询次数计数器
        int count = 0;
        while (true) {
            if (lockA.tryLock()) { // 尝试获取锁
                System.out.println("线程 1:获取到锁 A!");
                try {
                    Thread.sleep(1000);
                    System.out.println("线程 1:等待获取 B...");
                    if (lockB.tryLock()) { // 尝试获取锁
                        try {
                            System.out.println("线程 1:获取到锁 B!");
                        } finally {
                            lockB.unlock(); // 释放锁
                            System.out.println("线程 1:释放锁 B.");
                            break;
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lockA.unlock(); // 释放锁
                    System.out.println("线程 1:释放锁 A.");
                }
            }

            // 判断是否已经超过最大次数限制
            if (count++ > maxCount) {
                // 终止循环
                System.out.println("轮询锁获取失败,记录日志或执行其他失败策略");
                return;
            }

            // 等待一秒再继续尝试获取锁
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Hasil pelaksanaan kod di atas adalah seperti berikut:

Bagaimana untuk menyelesaikan masalah apabila menggunakan kunci mengundi di Jawa?

Dapat dilihat daripada keputusan di atas bahawa selepas kami memperbaikinya, kunci pengundian tidak akan menghadapi masalah gelung tak terhingga Ia akan menamatkan pelaksanaan selepas mencuba beberapa kali.

Masalah 2: Kebuluran benang

Masa menunggu pengundian kunci pengundian kami di atas ialah masa tetap, seperti yang ditunjukkan dalam kod berikut:

rreee

Ini akan menyebabkan masalah kebuluran benang dalam keadaan khas, iaitu masalah kunci pengundian tidak pernah dapat kunci, seperti contoh berikut.

Contoh balas

// 等待 1s 再尝试获取(轮询)锁
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}

Keputusan pelaksanaan kod di atas adalah seperti berikut:

Bagaimana untuk menyelesaikan masalah apabila menggunakan kunci mengundi di Jawa?

Seperti yang dapat dilihat daripada keputusan di atas, benang 1 (kunci pengundian) tidak berjaya memperoleh kunci Sebab untuk keputusan ini ialah benang 1 mempunyai masa menunggu tetap 1s untuk setiap tinjauan pendapat, dan utas 2 juga mempunyai kekerapan yang sama, memperolehnya. kunci setiap 1s, jadi Ini akan menyebabkan Thread 2 sentiasa berjaya memperoleh kunci terlebih dahulu, manakala Thread 1 akan sentiasa berada dalam situasi "kebuluran" Proses pelaksanaan adalah seperti yang ditunjukkan dalam rajah di bawah:

Bagaimana untuk menyelesaikan masalah apabila menggunakan kunci mengundi di Jawa?

Versi dioptimumkan

Seterusnya, kita boleh menambah baik masa menunggu tetap kunci pengundian,

kepada kaedah masa tetap + masa rawak, supaya kita dapat mengelakkan masalah memperoleh kunci Kekerapan adalah konsisten, yang menyebabkan masalah "kebuluran" kunci pengundian Kod pelaksanaan khusus adalah seperti berikut:

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

public class SolveDeadLockExample {

    public static void main(String[] args) {
        Lock lockA = new ReentrantLock(); // 创建锁 A
        Lock lockB = new ReentrantLock(); // 创建锁 B

        // 创建线程 1(使用轮询锁)
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 调用轮询锁
                pollingLock(lockA, lockB, 3);
            }
        });
        t1.start(); // 运行线程

        // 创建线程 2
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    lockB.lock(); // 加锁
                    System.out.println("线程 2:获取到锁 B!");
                    try {
                        System.out.println("线程 2:等待获取 A...");
                        lockA.lock(); // 加锁
                        try {
                            System.out.println("线程 2:获取到锁 A!");
                        } finally {
                            lockA.unlock(); // 释放锁
                        }
                    } finally {
                        lockB.unlock(); // 释放锁
                    }
                    // 等待一秒之后继续执行
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        t2.start(); // 运行线程
    }

    /**
     * 轮询锁
     */
    public static void pollingLock(Lock lockA, Lock lockB, int maxCount) {
        // 循环次数计数器
        int count = 0;
        while (true) {
            if (lockA.tryLock()) { // 尝试获取锁
                System.out.println("线程 1:获取到锁 A!");
                try {
                    Thread.sleep(100); // 等待 0.1s(获取锁需要的时间)
                    System.out.println("线程 1:等待获取 B...");
                    if (lockB.tryLock()) { // 尝试获取锁
                        try {
                            System.out.println("线程 1:获取到锁 B!");
                        } finally {
                            lockB.unlock(); // 释放锁
                            System.out.println("线程 1:释放锁 B.");
                            break;
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lockA.unlock(); // 释放锁
                    System.out.println("线程 1:释放锁 A.");
                }
            }

            // 判断是否已经超过最大次数限制
            if (count++ > maxCount) {
                // 终止循环
                System.out.println("轮询锁获取失败,记录日志或执行其他失败策略");
                return;
            }

            // 等待一秒再继续尝试获取锁
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Keputusan pelaksanaan kod di atas adalah seperti berikut:

Bagaimana untuk menyelesaikan masalah apabila menggunakan kunci mengundi di Jawa?Ia boleh dilihat daripada keputusan di atas bahawa selepas benang 1 (kunci pengundian) menambah masa menunggu secara rawak, masalah kebuluran benang tidak akan berlaku.

Atas ialah kandungan terperinci Bagaimana untuk menyelesaikan masalah apabila menggunakan kunci mengundi di Jawa?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam