synchronized三中写法以及死锁的概念

synchronized有三种写法:
    第一种:同步代码块
        灵活
        synchronized(线程共享对象){
            同步代码块;
        }

/*
线程同步机制的语法是:
    synchronized(){
        //线程同步代码块。
    }
    synchronized后面小括号中传的这个数据是相当关键的。
    这个数据必须是多线程共享的数据,才能达到多线程排队。

    ()中写什么?
        那要看你想让那些线程同步。
        假设t1,t2,t3,t4,t5有五个线程,
        你只希望t1,t2,t3排队,t4,t5不需要排队。怎么办?
        一定要在()中写一个t1,t2,t3共享的对象。而这个对象
        对于t4,t5来说不是共享的。

    java语言中,任何一个对象都有一把锁,其实这把锁就是标记。(只是把它叫做锁)
    100个对象,100把锁。

    以下代码的执行原理?

 */
Object obj2=new Object();
synchronized(this){
//synchronized(actno){
//synchronized(obj){
//synchronized("abc"){//"abc"在字符串常量池当中
//synchronized(obj2){//因为obj2不是共享对象,这样编写就不安全了。
    double before=this.getBalance();
    double after=this.balance-money;
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    this.setBalance(after);
}

    第二种:在实例方法上使用synchronized
        表示共享对象一定是this
        并且同步代码块是整个方法体

/*
在实例方法上可以使用synchronized吗?可以的
    synchronized出现在实例方法上,一定锁的是this。
    只能是this,不能是其他对象
    所以这种方式不灵活。
    还有一个缺点:synchronized出现在实例方法上,
    表示整个方法体都需要同步,可能会无故扩大同步的
    范围,导致程序的执行效率降低,这种方式不常用。

    synchronized 使用在实例方法上有什么优点:节俭了
    如果共享的对象就是this,并且需要同步的代码块是整个
    方法体,建议使用这种方式。

 */
public synchronized void withdraw(double money){

    double before=this.getBalance();

    double after=this.balance-money;

    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    this.setBalance(after);
}

    第三种:在静态方法上使用synchronized
        表示找类锁
        类锁永远只有一把。
        结算创建了100个对象,那类锁也只有一把

 

以后开发中怎么解决线程安全问题?
    不能一上来就是使用synchronized
    synchronized会让程序的执行效率降低,用户体验不好。
    系统的吞吐量降低,用户体验差。在不得已的情况下,再
    使用线程同步机制

    第一种方案:尽量使用局部变量代替实例变量和静态变量。
    第二种方案:如果必须是实例变量,那么可以考虑创建多个对象,这样对象就不共享了。
    (一个线程一个对象)对象不共享就没有数据安全问题。
    第三种方案:如果不能使用局部变量,对象也不能创建多个,这个时候就只能使用
    synchronized了,线程同步机制。

 

synchronized面试题

1、doOther()方法的执行的时候需要等待doSome()方法的结束吗?
    不需要,因为doOther()方法没有synchronized关键字。
    synchronized锁的对象是this,这个对象,因为doOther()
    方法没有synchronized关键字,所以不需要访问已经被锁
    住的MyClass对象

public class Exam01 {
    public static void main(String[] args) {
        MyClass mc=new MyClass();

        MyThread t1=new MyThread(mc);
        MyThread t2=new MyThread(mc);

        t1.setName("t1");
        t2.setName("t2");

        t1.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.start();
    }
}
class MyThread extends Thread{
    private MyClass mc;

    public MyThread(MyClass mc){
        this.mc=mc;
    }

    @Override
    public void run() {
        if(Thread.currentThread().getName().equals("t1")){
            mc.doSome();
        }
        if(Thread.currentThread().getName().equals("t2")){
            mc.doOther();
        }
    }
}

class MyClass{
    public synchronized void doSome(){
        System.out.println("doSome begin");
        try {
            Thread.sleep(1000*10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("doSome over");
    }

    public void doOther(){
        System.out.println("doOther begin");
        System.out.println("doOther over");
    }
}

2、对以上代码实现以下改变

doOther()方法的执行的时候需要等待doSome()方法的结束吗?

需要

public synchronized void doOther(){
    System.out.println("doOther begin");
    System.out.println("doOther over");
}

3、对以上代码实现以下改变

doOther()方法的执行的时候需要等待doSome()方法的结束吗?

不需要,因为MyClass对象有两个。

MyClass mc1=new MyClass();
MyClass mc2=new MyClass();

MyThread t1=new MyThread(mc1);
MyThread t2=new MyThread(mc2);

public synchronized void doOther(){
    System.out.println("doOther begin");
    System.out.println("doOther over");
}

4、对以上代码实现以下改变

doOther()方法的执行的时候需要等待doSome()方法的结束吗?

需要,因为静态方法是类锁,类锁不管创建了几个对象,类锁只有一把

public synchronized static void doSome(){
    System.out.println("doSome begin");
    try {
        Thread.sleep(1000*10);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("doSome over");
}

public synchronized static void doOther(){
    System.out.println("doOther begin");
    System.out.println("doOther over");
}

 

死锁的概念

以下代码为死锁代码:

public class DeadLock {
    public static void main(String[] args) {
        Object o1=new Object();
        Object o2=new Object();
        MyThread1 t1=new MyThread1(o1,o2);
        MyThread2 t2=new MyThread2(o1,o2);

        t1.setName("t1");
        t2.setName("t2");

        t1.start();
        t2.start();
    }
}

class MyThread1 extends Thread{
    Object o1;
    Object o2;
    public MyThread1(Object o1,Object o2){
        this.o1=o1;
        this.o2=o2;
    }

    @Override
    public void run() {
        synchronized (o1) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (o2) {
            }
        }
    }
}

class MyThread2 extends Thread{
    Object o1;
    Object o2;
    public MyThread2(Object o1,Object o2){
        this.o1=o1;
        this.o2=o2;
    }

    @Override
    public void run() {
        synchronized(o2){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized(o1){
            }
        }
    }
}

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值