java学习初探十八之线程的线程同步_锁机制_synchronized

一、线程同步
异步线程模型:t1线程执行t1的,t2线程执行t2的,两个线程之间谁也不等谁。
同步线程模型:t1线程和t2线程执行,当t1线程必须等t2线程执行结束之后,t1线程才能执行。

什么时候要同步?为什么要引入线程同步?
1.为了数据的安全。尽管应用程序的使用率降低,但是为了保证数据是安全的,必须加入线程同步机制。线程同步机制使程序变成了(等同)单线程
2.什么情况下要使用线程同步?
第一、必须是多线程环境;
第二、多线程环境共享同一个数据;
第三、共享数据涉及修改操作。

1.以下例子为没使用线程同步的情况:

package xiancheng2;
/*
 * 以下程序演示取款离职。以下程序不使用线程同步机制,
 * 多线程同时对同一个账号进行取款操作,会出现什么问题?
 */
public class ThreadTest1 {
    public static void main(String[] args) {
        //创建公共账号
        Account act=new Account("actno-001",5000);

        //创建线程对同一个账号取款
        Proccessor p=new Proccessor(act);

        Thread t1=new Thread(p);

        Thread t2=new Thread(p);

        t1.start();
        t2.start();
    }
}
//取款线程
class Proccessor implements Runnable{
    //账号
    Account act;
    public Proccessor(Account act) {
        this.act=act;
    }
    public void run() {
        act.withdraw(1000.0);
        System.out.println("取款成功,余额"+act.getBalance());
    }
}

//账号
class Account{
    private String actno;
    private double balance;
    public Account() {}
    public Account(String actno,double balance) {
        this.balance=balance;
        this.actno=actno;
    }
    public String getActno() {
        return actno;
    }
    public void setActno(String actno) {
        this.actno = actno;
    }
    public double getBalance() {
        return balance;
    }
    public void setBalance(double balance) {
        this.balance = balance;
    }
    //对外提供一个取款方法
    public void withdraw(double money) {//对当前账号进行取款操作
        double after=this.balance-money;
        //延迟
        try {Thread.sleep(5000);} catch (Exception e) { e.printStackTrace();    }
        //更新
        this.setBalance(after);
    }
}

输出:

取款成功,余额4000.0
取款成功,余额4000.0

显而易见,这是不正确的。
2.以下程序使用线程机制控制(synchronized):

package xiancheng2;
/*
 * 以下程序演示取款离职。以下程序使用线程同步机制,
 * 多线程同时对同一个账号进行取款操作,会出现什么问题?
 */
public class ThreadTest1 {
    public static void main(String[] args) {
        //创建公共账号
        Account act=new Account("actno-001",5000);

        //创建线程对同一个账号取款
        Proccessor p=new Proccessor(act);

        Thread t1=new Thread(p);

        Thread t2=new Thread(p);

        t1.start();
        t2.start();
    }
}
//取款线程
class Proccessor implements Runnable{
    //账号
    Account act;
    public Proccessor(Account act) {
        this.act=act;
    }
    public void run() {
        act.withdraw(1000.0);
        System.out.println("取款成功,余额"+act.getBalance());
    }
}

//账号
class Account{
    private String actno;
    private double balance;
    public Account() {}
    public Account(String actno,double balance) {
        this.balance=balance;
        this.actno=actno;
    }
    public String getActno() {
        return actno;
    }
    public void setActno(String actno) {
        this.actno = actno;
    }
    public double getBalance() {
        return balance;
    }
    public void setBalance(double balance) {
        this.balance = balance;
    }
    //对外提供一个取款方法
    public void withdraw(double money) {//对当前账号进行取款操作

        //把需要同步的代码,放到同步语句块中。
        synchronized (this) {//填共享对象
            double after=this.balance-money;
            //延迟
            try {Thread.sleep(5000);} catch (Exception e) { e.printStackTrace();    }
            //更新
            this.setBalance(after);
        }

    }
}

输出:

取款成功,余额4000.0
取款成功,余额3000.0

3.执行原理:
t1线程执行到此处,遇到,synchronized关键字,就会去找this的对象锁。如果找到this对象锁,则进入同步语句块中执行程序。当同步语句块中的语句块执行结束后,t1线程归还this的对象锁。

在t1线程执行同步语句块的过程中,如果t2线程也过来执行,也遇到synchronized关键字,所以也去找this的对象锁,但是该对象锁被t1线程所有,只能在这等待this对象的归还。

sychronized关键字添加到成员方法上,线程拿走的也是this的对象锁。

package xiancheng2;
/*
 * 以下程序演示取款离职。以下程序不使用线程同步机制,
 * 多线程同时对同一个账号进行取款操作,会出现什么问题?
 */
public class ThreadTest1 {
    public static void main(String[] args) {
        //创建公共账号
        Account act=new Account("actno-001",5000);

        //创建线程对同一个账号取款
        Proccessor p=new Proccessor(act);

        Thread t1=new Thread(p);

        Thread t2=new Thread(p);

        t1.start();
        t2.start();
    }
}
//取款线程
class Proccessor implements Runnable{
    //账号
    Account act;
    public Proccessor(Account act) {
        this.act=act;
    }
    public void run() {
        act.withdraw(1000.0);
        System.out.println("取款成功,余额"+act.getBalance());
    }
}

//账号
class Account{
    private String actno;
    private double balance;
    public Account() {}
    public Account(String actno,double balance) {
        this.balance=balance;
        this.actno=actno;
    }
    public String getActno() {
        return actno;
    }
    public void setActno(String actno) {
        this.actno = actno;
    }
    public double getBalance() {
        return balance;
    }
    public void setBalance(double balance) {
        this.balance = balance;
    }
    //对外提供一个取款方法
    public synchronized void withdraw(double money) {//对当前账号进行取款操作
            double after=this.balance-money;
            //延迟
            try {Thread.sleep(5000);} catch (Exception e) { e.printStackTrace();    }
            //更新
            this.setBalance(after);
    }
}

为了精确控制,2的添加方法更适合些。

4.面试题

package xiancheng2;
/*
 * 面试题
 * t1线程没有结束的时候,t2需不需要等t1结束?
 * 答案:不需要。
 * 因为m2方法上没有synchronized,所以不需要找对象锁。
 * 如果m2方法上加了synchronized,则需要找对象锁,等待m1方法结束,释放对象锁。
 * 注意:t1、t2一定要共享同一个对象,才能谈同步机制。
 */
public class ThreadTest2 {
    public static void main(String[] args) throws InterruptedException {
        MyClass mc=new MyClass();
        myThread thread=new myThread(mc);

        Thread t1=new Thread(thread);
        t1.setName("t1");
        Thread t2=new Thread(thread);
        t2.setName("t2");

        //启动线程
        t1.start();

        //延迟保证t1线程先启动,并执行run
        Thread.sleep(1000);
        t2.start();

    }
}
class myThread implements Runnable{
    MyClass mc;
    myThread(MyClass mc){
        this.mc=mc;
    }
    public void run() {
        if(Thread.currentThread().getName().equals("t1")) {
            mc.m1();
        }
        if(Thread.currentThread().getName().equals("t2")) {
            mc.m2();
        }
    }
}
class MyClass{
    public synchronized void m1() {
        //休眠10s
        try{Thread.sleep(10000);}catch (InterruptedException e) {}
        System.out.println("m1........");
    }
    public void m2() {
        System.out.println("m2........");
    }
}

输出结果:

m2........
m1........

5.类锁 ,修饰静态方法

package xiancheng2;
/*
 * 类锁,类只有一个,所以锁是类级别的,只有一个
 */
public class ThreadTest3 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(new Proccessor());
        t1.setName("t1");
        Thread t2=new Thread(new Proccessor());
        t2.setName("t2");
        t1.start();
        Thread.sleep(1000);
        t2.start();
    }
}
class Proccessor implements Runnable{
    public void run() {
        if("t1".equals(Thread.currentThread().getName())) {
            Myclass.m1();
        }
        if("t2".equals(Thread.currentThread().getName())) {
            Myclass.m2();
        }
    }
}
class Myclass{
    //synchronized添加到静态方法上,线程执行此方法的时候会找类锁
    public synchronized static void m1() {
        try {
            Thread.sleep(10000);
        } catch (Exception e) {
        }
        System.out.println("m1.......");
    }
    //不会等m1结束,因为该方法没有被sychronized修饰。
    /*public static void m2() {
        System.out.println("m2.......");
    }
    */
    //会等m1结束,因为该方法没有被sychronized修饰。线程执行该代码需要“类锁”,而类锁只有一个
    public synchronized static void m2() {
        System.out.println("m2.......");
    }
}

6.死锁

package xiancheng2;
/*
 * 死锁
 */
public class ThreadTest1 {
    public static void main(String[] args) {
        Object o1=new Object();
        Object o2=new Object();

        Thread t1=new Thread(new T1(o1,o2));
        Thread t2=new Thread(new T2(o1,o2));
        t1.start();
        t2.start();

    }
}
class T1 implements Runnable{
    Object o1;
    Object o2;
    T1(Object o1,Object o2){
        this.o1=o1;
        this.o2=o2;
    }
    public void run() {
        //先锁o1,再锁o2
        synchronized (o1) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t11....");
            synchronized (o2) {
                System.out.println("t1....");
            }
        }
    }
}
class T2 implements Runnable{
    Object o1;
    Object o2;
    T2(Object o1,Object o2){
        this.o1=o1;
        this.o2=o2;
    }
    public void run() {
        //先锁o2,再锁o1
        synchronized (o2) {
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
            }
            System.out.println("t22....");
            synchronized (o1) {
                System.out.println("t2....");
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值