侧边栏壁纸
博主头像
DJ's Blog博主等级

行动起来,活在当下

  • 累计撰写 133 篇文章
  • 累计创建 51 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

【Java】Synchronized

Administrator
2022-04-05 / 0 评论 / 0 点赞 / 69 阅读 / 4895 字

【Java】Synchronized

简介

synchronized是Java中的一个关键字,也就是说是Java语言内置的特性。
如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:

  1. 获取锁的线程执行完了该代码块,然后线程释放对锁的占有。
  2. 线程执行发生异常,此时JVM会让线程自动释放锁。

语法

修饰代码块

synchronized(需要一个任意的对象(锁)){
	代码块中放操作共享数据的代码。
}

修饰方法

synchronized
method(){
	...
}

代码示例

public class MySynchronized {
    private String name;
    public MySynchronized() {
    }
    public MySynchronized(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public static void main(String[] args) {
        MySynchronized mySynchronized = new MySynchronized("a");
        MySynchronized mySynchronized2 = new MySynchronized("b");
		// 创建thread1线程
        new Thread("thread1") {
            @Override
            public void run() {
                System.out.println(this.getName() + "线程的run方法被调用……");
                synchronized (mySynchronized) {
                    try {
                        System.out.println("锁名称为:" + mySynchronized.getName());
                        System.out.println(this.getName() + " start");
                        Thread.sleep(5000);
                        System.out.println(this.getName() + "醒了");
                        System.out.println(this.getName() + " end");
                        // 如果发生异常,JVM会自动将锁释放
                        int i = 1 / 0;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        // 创建thread2线程
        new Thread("thread2") { 
            @Override
            public void run() {
                System.out.println(this.getName() + "线程的run方法被调用……");
                // 如果不是同一把锁,线程2不用等待直接执行
                //synchronized (mySynchronized2) {
                // 争抢同一把锁时,线程1没释放之前,线程2只能等待
                synchronized (mySynchronized) {
                    System.out.println("锁名称为:" + mySynchronized.getName());
                    System.out.println(this.getName() + " start");
                    System.out.println(this.getName() + " end");
                }
            }
        }.start();
    }
}

具体示例

火车售票系统,客票一共有100张,分三个窗口来卖。

package org.djflying.bigdata.java.thread;
public class TicketWindow implements Runnable {
    private int tickets;
    public TicketWindow() {
    }
    public TicketWindow(int tickets) {
        this.tickets = tickets;
    }
    public int getTickets() {
        return tickets;
    }
    public void setTickets(int tickets) {
        this.tickets = tickets;
    }
    /**
     * 销售一张客票
     */
    public void sellOne() {
        this.tickets--;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (this) {
                if (this.getTickets() > 0) {
                    System.out.println("还剩余票:" + this.getTickets() + "张");
                    this.sellOne();
                    System.out.println(Thread.currentThread().getName() + "卖出一张火车票,还剩" + this.getTickets() + "张");
                } else {
                    System.out.println("余票不足,暂停出售!");
                    break;
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) {
        TicketWindow ticketWindow = new TicketWindow(100);
        Thread thread1 = new Thread(ticketWindow, "一号窗口");
        Thread thread2 = new Thread(ticketWindow, "二号窗口");
        Thread thread3 = new Thread(ticketWindow, "三号窗口");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

缺陷

  • 如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,试想一下,这多么影响程序执行效率。
    因此就需要有一种机制可以不让等待的线程一直无期限地等待下去(比如只等待一定的时间或者能够响应中断),通过Lock就可以办到。
  • 当有多个线程读写文件时,读操作和写操作会发生冲突现象,写操作和写操作会发生冲突现象,但是读操作和读操作不会发生冲突现象。
    如果采用synchronized关键字来实现同步的话,就会导致一个问题:如果多个线程都只是进行读操作,当一个线程在进行读操作时,其他线程只能等待无法进行读操作。
    因此就需要一种机制来使得多个线程都只是进行读操作时,线程之间不会发生冲突,通过Lock就可以办到。
    另外,通过Lock可以知道线程有没有成功获取到锁。这个是synchronized无法办到的。
    总的来说,也就是说Lock提供了比synchronized更多的功能。
0

评论区