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

来源:互联网 发布:mac压缩包加密 编辑:程序博客网 时间:2024/05/17 05:53

一、线程同步
异步线程模型: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........
原创粉丝点击