synchronized关键字实现多线程的3种方式:
1. 继承Thread类2. 实现Runnable接口3. 匿名类的方式注: 启动线程是start()方法,run()并不能启动一个新的线程
一.继承线程类
使用多线程,就可以做到盖伦在攻击提莫的同时,赏金猎人也在攻击盲僧 设计一个类KillThread 继承Thread,并且重写run方法 启动线程办法: 实例化一个KillThread对象,并且调用其start方法 就可以观察到 赏金猎人攻击盲僧的同时,盖伦也在攻击提莫
package multiplethread; import charactor.Hero; public class KillThread extends Thread{ private Hero h1; private Hero h2; public KillThread(Hero h1, Hero h2){ this.h1 = h1; this.h2 = h2; } public void run(){ while(!h2.isDead()){ h1.attackHero(h2); } }}
package multiplethread; import charactor.Hero; public class TestThread { public static void main(String[] args) { Hero gareen = new Hero(); gareen.name = "盖伦"; gareen.hp = 616; gareen.damage = 50; Hero teemo = new Hero(); teemo.name = "提莫"; teemo.hp = 300; teemo.damage = 30; Hero bh = new Hero(); bh.name = "赏金猎人"; bh.hp = 500; bh.damage = 65; Hero leesin = new Hero(); leesin.name = "盲僧"; leesin.hp = 455; leesin.damage = 80; KillThread killThread1 = new KillThread(gareen,teemo); killThread1.start(); KillThread killThread2 = new KillThread(bh,leesin); killThread2.start(); } }
二.实现Runnable接口
创建类Battle,实现Runnable接口
启动的时候,首先创建一个Battle对象,然后再根据该battle对象创建一个线程对象,并启动package multiplethread; import charactor.Hero; public class Battle implements Runnable{ private Hero h1; private Hero h2; public Battle(Hero h1, Hero h2){ this.h1 = h1; this.h2 = h2; } public void run(){ while(!h2.isDead()){ h1.attackHero(h2); } }}
package multiplethread; import charactor.Hero; public class TestThread { public static void main(String[] args) { Hero gareen = new Hero(); gareen.name = "盖伦"; gareen.hp = 616; gareen.damage = 50; Hero teemo = new Hero(); teemo.name = "提莫"; teemo.hp = 300; teemo.damage = 30; Hero bh = new Hero(); bh.name = "赏金猎人"; bh.hp = 500; bh.damage = 65; Hero leesin = new Hero(); leesin.name = "盲僧"; leesin.hp = 455; leesin.damage = 80; Battle battle1 = new Battle(gareen,teemo); new Thread(battle1).start(); Battle battle2 = new Battle(bh,leesin); new Thread(battle2).start(); } }
三.匿名类
使用匿名类,继承Thread,重写run方法,直接在run方法中写业务代码 匿名类的一个好处是可以很方便的访问外部的局部变量。 前提是外部的局部变量需要被声明为final。(JDK7以后就不需要了)
package multiplethread; import charactor.Hero; public class TestThread { public static void main(String[] args) { Hero gareen = new Hero(); gareen.name = "盖伦"; gareen.hp = 616; gareen.damage = 50; Hero teemo = new Hero(); teemo.name = "提莫"; teemo.hp = 300; teemo.damage = 30; Hero bh = new Hero(); bh.name = "赏金猎人"; bh.hp = 500; bh.damage = 65; Hero leesin = new Hero(); leesin.name = "盲僧"; leesin.hp = 455; leesin.damage = 80; //匿名类 Thread t1= new Thread(){ public void run(){ //匿名类中用到外部的局部变量teemo,必须把teemo声明为final //但是在JDK7以后,就不是必须加final的了 while(!teemo.isDead()){ gareen.attackHero(teemo); } } }; t1.start(); Thread t2= new Thread(){ public void run(){ while(!leesin.isDead()){ bh.attackHero(leesin); } } }; t2.start(); } }
四.常见线程方法:
五.Concurrency 问题(并发性):
package multiplethread; import java.text.SimpleDateFormat;import java.util.Date; public class TestThread { public static String now(){ return new SimpleDateFormat("HH:mm:ss").format(new Date()); } public static void main(String[] args) { final Object someObject = new Object(); Thread t1 = new Thread(){ public void run(){ try { System.out.println( now()+" t1 线程已经运行"); System.out.println( now()+this.getName()+ " 试图占有对象:someObject"); synchronized (someObject) { System.out.println( now()+this.getName()+ " 占有对象:someObject"); Thread.sleep(5000); System.out.println( now()+this.getName()+ " 释放对象:someObject"); } System.out.println(now()+" t1 线程结束"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; t1.setName(" t1"); t1.start(); Thread t2 = new Thread(){ public void run(){ try { System.out.println( now()+" t2 线程已经运行"); System.out.println( now()+this.getName()+ " 试图占有对象:someObject"); synchronized (someObject) { System.out.println( now()+this.getName()+ " 占有对象:someObject"); Thread.sleep(5000); System.out.println( now()+this.getName()+ " 释放对象:someObject"); } System.out.println(now()+" t2 线程结束"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; t2.setName(" t2"); t2.start(); } }
17:00:34 t2 线程已经运行17:00:34 t1 线程已经运行17:00:34 t2 试图占有对象:someObject17:00:34 t1 试图占有对象:someObject17:00:34 t2 占有对象:someObject17:00:39 t2 释放对象:someObject17:00:39 t2 线程结束17:00:39 t1 占有对象:someObject17:00:44 t1 释放对象:someObject17:00:44 t1 线程结束
在recover前,直接加上synchronized ,其所对应的同步对象,就是this
和hurt方法达到的效果是一样外部线程访问gareen的方法,就不需要额外使用synchronized 了//回血 //直接在方法前加上修饰符synchronized //其所对应的同步对象,就是this //和hurt方法达到的效果一样 public synchronized void recover(){ hp=hp+1; } //掉血 public void hurt(){ //使用this作为同步对象 synchronized (this) { hp=hp-1; } }