您的位置:首页 > 编程语言 > Java开发

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

2017-12-21 20:00 393 查看
一、线程同步

异步线程模型: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....");
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: