b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

Java多线程2.线程生命周期,线程安全性,死锁

电脑杂谈  发布时间:2020-07-05 02:06:58  来源:网络整理

多线程避免死锁_线程 死锁_线程死锁

线程具有生命周期. 创建线程并在运行后执行相关操作后,终点必须是死亡.

如下所示: 演示线程的生命周期:

线程的中年分为五个阶段

在这五个阶段中,不一定有阻塞多线程避免死锁,还有其他几种状态,线程的最终结果是死亡.

1. 正常状态下的变化:

2. 阻止状态有所改变

当多个线程之间共享数据时,将出现线程安全问题.

示例:

三个线程同时抓取100张票. 添加睡眠时,票据很重,并且错误票据的可能性大大增加,因为该票据尚未在上一个线程中被票据购票-当下一个线程也进入时,由于共享数据问题导致了错误票据

代码如下:

线程 死锁_线程死锁_多线程避免死锁

public class WindowTest {
    public static void main(String[] args) {
        Window win = new Window();
        Thread t1 = new Thread(win);
        Thread t2 = new Thread(win);
        Thread t3 = new Thread(win);
        t1.start();
        t2.start();
        t3.start();
    }
}
class Window implements Runnable {
    private int ticket = 100;
    @Override
    public void run() {
        while (true) {
            if (ticket > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ": 卖票,票号为:" + ticket);
                ticket--;
            } else {
                break;
            }
        }
    }
}

运行结果中的票证编号为-1,即票证错误.

如何解决?

思想: 当一个线程对共享数据进行操作时,当前线程将锁定资源,而其他线程则无法对共享数据进行操作. 在这种情况下,即使线程被阻塞,也不允许其他线程对共享数据进行操作.

	synchronized(同步监视器){
	//需要被同步的代码
	}

请记住: 多个线程共享一个锁,并且该锁是唯一的.

描述: 添加了同步监视器之后,在同步代码块中,有一个线程可以智能地运行,其他线程在等待,因此该块相当于一个线程,因此效率较低.

在使用继承创建多线程时,请小心将其用作同步监视器,请考虑将当前类用作同步监视器,例如: Window2.class

示例:

同步代码块以解决线程安全问题,如下所示:

线程死锁_线程 死锁_多线程避免死锁

public class WindowTest1 {
    public static void main(String[] args) {
        Window1 win = new Window1();
        Thread t1 = new Thread(win);
        Thread t2 = new Thread(win);
        Thread t3 = new Thread(win);
        t1.start();
        t2.start();
        t3.start();
    }
}
class Window1 implements Runnable {
    private int ticket = 100;
    //创建一个唯一对象,做为锁,锁可以使任何对象,但切记锁智能有一把
    Object obj = new Object();
    @Override
    public void run() {
        while (true) {
            //这里也可以用this 替换obj,因为我们只new了一个Window
            synchronized (obj) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ": 卖票,票号为:" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}

目前,运行结果中没有任何人投票

如果在一个方法中完全声明了操作共享数据的代码,那么我们最好将此方法声明为已同步,并在方法声明中添加已同步的标识符.

以下代码演示了如何使用同步方法解决线程安全问题:

public class WindowTest3 {
    public static void main(String[] args) {
        Window3 win = new Window3();
        Thread t1 = new Thread(win);
        Thread t2 = new Thread(win);
        Thread t3 = new Thread(win);
        t1.start();
        t2.start();
        t3.start();
    }
}
class Window3 implements Runnable {
    private int ticket = 100;
    //创建一个唯一对象,做为锁,锁可以使任何对象,但切记锁智能有一把
    @Override
    public void run() {
        while (true) {
            this.show();
            if (ticket <= 0) {
                break;
            }
        }
    }
    private synchronized void show() {//同步监视器中,这块默认的锁就是this
        if (ticket > 0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ": 卖票,票号为:" + ticket);
            ticket--;
        }
    }
}

这时,不会显示错误的票证数据

注意: 因为此时只有一个Window3对象,所以同步监视器默认为该对象.

在JDK 5.0中,可以使用Lock方法解决线程安全问题.

以下代码演示了如何使用Lock方法手动锁定和解锁

线程 死锁_多线程避免死锁_线程死锁

在run方法中,程序首先手动锁定以确保在当前线程获得锁定之后其他线程不会进入. 当执行最终到达时,将释放锁,然后其他线程可以进入.

package com.jerry.thread6;
import java.util.concurrent.locks.ReentrantLock;
public class WindowTest5 {
    public static void main(String[] args) {
        Window5 win = new Window5();
        Thread t1 = new Thread(win);
        Thread t2 = new Thread(win);
        Thread t3 = new Thread(win);
        t1.start();
        t2.start();
        t3.start();
    }
}
class Window5 implements Runnable {
    private int ticket = 100;
    private ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true) {
            try {
                //手动加锁
                lock.lock();
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ": 卖票,票号为:" + ticket);
                    ticket--;
                } else {
                    break;
                }
            } finally {
                //手动解锁
                lock.unlock();
            }
        }
    }
}

摘要:

访谈问题1: 同步方法和锁定方法有什么区别?

相似点: 两者都可以解决线程安全问题.

区别: 锁定模式是手动锁定和解锁. 同步自动解锁. 执行同步方法或代码块后,同步监视器将自动释放(自动解锁). 手动锁定和解锁,更加灵活

面试问题2: 如何解决线程安全问题?

1)将同步关键字添加到同步代码块中

2)使用同步方法,即添加synced关键字的方法

3)使用ReentrantLock手动锁定和手动解锁


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-268830-1.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    • 王山山
      王山山

      这个就是教授的水平

    热点图片
    拼命载入中...