第二十八(线程的同步、守护线程、Timer 定时器)
/* 模拟ATM取款,不是线程同步机制,多线程同时对一个账户进行操作 t1 和 t2 异步编程模型:t1线程执行t1,t2线程执行的是t2,两个线程之间谁也不等于谁 同步编程模型:t1线程和t2线程执行,当t1线程必须等于t2的线程执行结果之后,t1线程才能执行 这是同步编程模型。 什么时候需要引入同步 1. 为了数据安全,尽管应用程序的使用率低,但是为了保证数据安全性,必须的加入线程同步机制 线程同步机制 使程序变成了(等同)单线程 2. 在什么条件下需要使用线程同步 <1> 必须是多线程环境 <2> 多线程环境在共享同一个数据时 <3> 共享的数据涉及到修改操作 */ public class ThreadTest01{ public static void main(String[] args){ // 创建一个公共账户 Account act = new Account("Ming",10000.0); // 创建线程对同一个账户进行取款 Thread t1 = new Thread(new Ming01(act)); Thread t2 = new Thread(new Ming01(act)); t1.start(); t2.start(); } } // 取款的线程 class Ming01 implements Runnable{ // Account 账户 Account act; Ming01(Account act){ this.act = act; } public void run(){ act.withdraw(2000.0); System.out.println("取款2000.0¥成功,余额为:" + act.getBalance()); } } // 银行账户 class Account{ private String actno; private double balance; // 账户余额 public Account(){} public Account(String actno,double balance){ this.actno = actno; this.balance = balance; } public void setActno(String actno){ this.actno = actno; } public String getActno(){ return actno; } public void setBalance(double balance){ this.balance = balance; } public double getBalance(){ return balance; } // 对外提供一个取款方法 public void withdraw(double money){ // 对账户进行取款操作 double after = balance - money; // 延迟 try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } // 更新账号余额 this.setBalance(after); } } //输出取款2000.0¥成功,余额为:8000.0
/* 以下程序使用线程同步机制保证数据安全型 */ public class ThreadTest02{ public static void main(String[] args){ // 创建一个公共账户 Account act = new Account("ming",10000.0); // 创建线程对同一个账户进行取款 Thread t1 = new Thread(new Ming01(act)); Thread t2 = new Thread(new Ming01(act)); t1.start(); t2.start(); } } // 取款的线程 class Ming01 implements Runnable{ // Account 账户 Account act; Ming01(Account act){ this.act = act; } public void run(){ act.withdraw(2000.0); System.out.println("取款2000.0¥成功,余额为:" + act.getBalance()); } } // 银行账户 class Account{ private String actno; private double balance; // 账户余额 public Account(){} public Account(String actno,double balance){ this.actno = actno; this.balance = balance; } public void setActno(String actno){ this.actno = actno; } public String getActno(){ return actno; } public void setBalance(double balance){ this.balance = balance; } public double getBalance(){ return balance; } // 对外提供一个取款方法 public void withdraw(double money){ /* 需要把同步的代码,放到同步的语句块中 t1线程执行到此处,遇到了 synchronized关键字,就会去找this的对象锁 如果找到了this的对象锁,则进入同步语句块 执行程序。 当同步语句块代码执行结束的时候,t1线程归还this的对象锁 在t1线程执行同步语句块的过程中,如果t2线程也过来执行以下代码,遇到synchronized关键字 所以也去找this对象锁,但是该对象被t1线程持有 只能在等待this对象的归还 */ synchronized(this){ // 对账户进行取款操作 double after = balance - money; // 延迟 try{ Thread.sleep(2000); }catch(InterruptedException e){ e.printStackTrace(); } // 更新账号余额 this.setBalance(after); } } }
/* 以下程序使用线程同步机制保证数据安全型 */ public class ThreadTest03{ public static void main(String[] args){ // 创建一个公共账户 Account act = new Account("ming",10000.0); // 创建线程对同一个账户进行取款 Thread t1 = new Thread(new Ming01(act)); Thread t2 = new Thread(new Ming01(act)); t1.start(); t2.start(); } } // 取款的线程 class Ming01 implements Runnable{ // Account 账户 Account act; Ming01(Account act){ this.act = act; } public void run(){ act.withdraw(2000.0); System.out.println("取款2000.0¥成功,余额为:" + act.getBalance()); } } // 银行账户 class Account{ private String actno; private double balance; // 账户余额 public Account(){} public Account(String actno,double balance){ this.actno = actno; this.balance = balance; } public void setActno(String actno){ this.actno = actno; } public String getActno(){ return actno; } public void setBalance(double balance){ this.balance = balance; } public double getBalance(){ return balance; } // 对外提供一个取款方法 // synchronized关键字 添加到成员方法上,线程拿走的也是this对象锁 public synchronized void withdraw(double money){ /* 需要把同步的代码,放到同步的语句块中 t1线程执行到此处,遇到了 synchronized关键字,就会去找this的对象锁 如果找到了this的对象锁,则进入同步语句块 执行程序。 当同步语句块代码执行结束的时候,t1线程归还this的对象锁 在t1线程执行同步语句块的过程中,如果t2线程也过来执行以下代码,遇到synchronized关键字 所以也去找this对象锁,但是该对象被t1线程持有 只能在等待this对象的归还 */ //synchronized(this){ // 对账户进行取款操作 double after = balance - money; // 延迟 try{ Thread.sleep(2000); }catch(InterruptedException e){ e.printStackTrace(); } // 更新账号余额 this.setBalance(after); //} } }
/* 定义一个用户线程 */ public class UserThread01{ public static void main(String[] args){ Runnable r1 = new UserTest(); Thread t1 = new Thread(r1,"t1"); t1.start(); for(int i = 0; i < 10; i++){ System.out.println(Thread.currentThread().getName() + " : " + i); } System.out.println("主线程结束 !"); } } class UserTest implements Runnable{ public void run(){ for(int i = 0; i < 10; i++){ System.out.println(Thread.currentThread().getName() + " : " + i); } } } ///////////////////////////////////////////////////////////////////////// /* 守护线程 其他所有的用户线程结束,则守护线程退出 守护线程一般都是无限执行的 设置了守护线程以后,当前主线程结束后,守护线程并没有把所有的数据输出就结束 也就是说 守护线程是为 用户线程服务的,当用户线程全部结束,守护线程会自动结束 跟我们的 java中自动垃圾回收机制GC 是一个原理 */ public class UserThread02{ public static void main(String[] args){ Thread t1 = new UserTest(); t1.setName("t1"); // 将t1这个用户线程 修改成守护线程 t1.setDaemon(true); t1.start(); // 主线程 for(int i = 0; i < 10; i++){ System.out.println(Thread.currentThread().getName() + " : " + i); try{ Thread.sleep(1000); } catch(InterruptedException e){} } System.out.println("主线程结束 !"); } } class UserTest extends Thread{ public void run(){ int i = 0; while(true){ i ++; System.out.println(Thread.currentThread().getName() +" : "+i); try{ Thread.sleep(1000); } catch(InterruptedException e){ } } } }
/* Timer定时器 */ import java.util.*; import java.text.*; public class TimerTest{ public static void main(String[] args){ Timer t = new Timer(); try{ Date d = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2015-1-20 23:35:30"); // 安排在指定的时间执行指定的任务 // t.schedule(new MyTimer(),d,1000*60*60*24); 24小时执行一次 t.schedule(new MyTimer(),d,1000*2); } catch(NullPointerException e){ e.printStackTrace(); } catch(IllegalArgumentException e){ e.printStackTrace(); } catch(IllegalStateException e){ e.printStackTrace(); } catch(ParseException e){ e.printStackTrace(); } } } class MyTimer extends TimerTask{ public void run(){ System.out.println(new Date()); } }