Java同步方法_synchronized 关键字&死锁问题

445 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

一、同步方法_synchronized 关键字

同步代码块可以有效解决线程的安全问题,当把共享资源的操作放在 synchronized 定义的区域内时,便为这些操作加了同步锁。

在方法前面同样可以使用 synchronized 关键字来修饰,被修饰的方法为同步方法,它能实现和同步代码块同样的功能,具体语法格式如下:

 synchronized 返回值类型 方法名([参数1,……]){}

synchronized 修饰的方法在某一时刻只允许一个线程访问,访问该方法的其他线程都会发生阻塞,直到当前线程访问完毕后,其他线程才有机会执行方法。

ExampleM13:

//同步方法
//定义 Ticket2 类实现 Runnable 接口
class Ticket2 implements Runnable {
    private int tickets = 10;

    public void run() {
        while (true) {
            saleTicket();   //调用售票方法
            if (tickets <= 0) {
                break;
            }
        }
    }
    //定义一个同步方法 saleTicket()
    private synchronized void saleTicket() {
        if (tickets>0) {
            try {
                Thread.sleep(10);   //经过的线程休眠 10 毫秒
            } catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"---卖出的票"+tickets--);
        }
    }
}

public class ExampleM13 {
    public static void main(String[] args) {
        Ticket2 ticket = new Ticket2(); //创建 Ticket1对象
        //创建并开启四个线程
        new Thread(ticket,"线程一").start();
        new Thread(ticket,"线程二").start();
        new Thread(ticket,"线程三").start();
        new Thread(ticket,"线程四").start();
    }

将售票代码抽取为售票方法 saleTicket (),并用 synchronized 关键字saleTicket()修饰为同步方法,然后在 run ()方法中调用该方法。

二、死锁问题_两个线程都需要对方所占用的锁

ExampleM14:

//死锁问题
class DeadLockThread implements Runnable {
    static Object chopsticks = new Object();    //定义 Object类型的 chopsticks(筷子)锁对象
    static Object knifeAndFork = new Object();  //定义 Object类型的 knifeAndFork(刀叉)锁对象
    private boolean flag;   //定义 Boolean 类型的变量 flag
    DeadLockThread(boolean flag) {  //定义有参的构造方法
        this.flag = flag;
    }
    public void run() {
        if (flag) {
            while (true) {
                synchronized (chopsticks) { //chopsticks 锁对象上的同步代码块
                    System.out.println(Thread.currentThread().getName()+"---if---chopsticks");
                    synchronized (knifeAndFork) {   //knifeAndFork 锁对象上的同步代码块
                        System.out.println(Thread.currentThread().getName()+"---if---knifeAndFork");
                    }
                }
            }
        }else {
            while (true) {
                synchronized (knifeAndFork) {   //knifeAndFork 锁对象上的同步代码块
                    System.out.println(Thread.currentThread().getName()+"---else---knifeAnfFork");
                    synchronized (chopsticks) { //chopsticks 锁对象上的同步代码块
                        System.out.println(Thread.currentThread().getName()+"---else---chopsticks");
                    }
                }
            }
        }
    }
}
public class ExampleM14 {
    public static void main(String[] args) {
        //创建两个 DeadLockThread对象
        DeadLockThread d1 = new DeadLockThread(true);
        DeadLockThread d2 = new DeadLockThread(false);
        //创建并开启两个线程
        new Thread(d1,"Chinese").start();   //创建开启线程 Chinese
        new Thread(d2,"American").start();  //创建开启线程 American
    }
}

创建了 ChineseAmerican 两个线程,分别执行 run ()方法中 if 和 else 代码块中的同步代码块。 Chinese 线程中拥有 chopsticks 锁,只有获得 knifeAndFork 锁才能执行完毕,而 American 线程拥有 knifeAndFork 锁,只有获得 chopsticks 锁才能执行完毕,两个线程都需要对方所占用的锁,但是都无法释放自己所拥有的锁,于是这两个线程都处于了挂起状态,从而造成了死锁