多线程
一、多线程实现
有三种实现多线程的方式:
1.继承Thread
2.接入runnerble
3.使用匿名类
二、实现实例
1 package threadtest; 2 3 public class TestThread { 4 5 public static void main(String[] args) { 6 // TODO Auto-generated method stub 7 Hero teemo = new Hero(); 8 teemo.name = "teemo"; 9 teemo.hp = 300; 10 teemo.damage = 30; 11 12 Hero lax = new Hero(); 13 lax.name = "lax"; 14 lax.hp = 400; 15 lax.damage = 50; 16 17 Hero leesin = new Hero(); 18 leesin.name = "leesin"; 19 leesin.hp = 500; 20 leesin.damage = 65; 21 22 Hero ezereal = new Hero(); 23 ezereal.name = "ezereal"; 24 ezereal.hp = 455; 25 ezereal.damage = 80; 26 27 /*1.创建多线程,继承线程类 28 KillThread killThread1 = new KillThread(teemo,lax); 29 killThread1.start(); 30 KillThread killThread2 = new KillThread(leesin,ezereal); 31 killThread2.start(); 32 */ 33 34 /*2.创建多线程,使用Runnerble()基础 35 * Runnable 接口中有run方法,但直接调用run方法 并不会启动一个新线程 36 * 因此,借助一个线程对象的start方法启动一个新线程 37 * 在创建Thread对象的时候,把b1作为构造方法的参数传递进去, 38 * 这个线程启动的时候,就会去执行battle1.run()方法了 39 Battle b1 = new Battle(teemo,lax); 40 new Thread(b1).start(); 41 Battle b2 = new Battle(leesin,ezereal); 42 new Thread(b2).start();*/ 43 44 /*3.创建多线程,使用匿名类*/ 45 //匿名类 46 Thread t1 = new Thread() { 47 public void run() { 48 //匿名类中用到外部的局部变量teemo,必须把teemo声明为final 49 //但JDK7以后,不是必须加final,系统会为你加上 50 while(!teemo.isDead()) { 51 lax.attackHero(teemo); 52 } 53 } 54 }; 55 56 t1.start(); 57 58 Thread t2 = new Thread() { 59 public void run() { 60 while(!leesin.isDead()) { 61 ezereal.attackHero(leesin); 62 } 63 } 64 }; 65 t2.start(); 66 67 } 68 69 }
三、英雄发动三次技能,技能充能5S后再发动。
public void adugen(){
while(true) {
for(num=1;num<4;num++) {
System.out.println(name+"take a adugen NO."+num);}
try {
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("take powering!");
try {
Thread.sleep(5000);
}catch(InterruptedException e) {
e.printStackTrace();
}}
}
四、同步
多线程同步问题指多个线程同时修改一个数据时,可能导致的问题。
Hero teemo = new Hero();
teemo.name = "teemo";
teemo.hp = 30000;
int n = 30000;
Thread[] addThreads = new Thread[n];
Thread[] reduceThreads = new Thread[n];
for(int i = 0; i <n ; i++) {
Thread t = new Thread() {
public void run() {
teemo.recover();
try {
Thread.sleep(100);
}catch(InterruptedException e) {
e.printStackTrace();
}
}};
t.start();
addThreads[i] = t;
}
//n个线程减少盖伦的HP
for(int i = 0;i<n;i++) {
Thread t = new Thread() {
public void run() {
teemo.hurt();
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();
reduceThreads[i] = t;
}
//等待所有增加线程结束
for(Thread t : addThreads) {
try {
t.join();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
//等待所有减少线程技术
for(Thread t:reduceThreads) {
try {
t.join();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
//代码执行到这里,所有增加和减少线程都结束了
//增加和减少线程的数量是一样的,每次都增加,减少1.
//那么所有线程都结束后,盖伦的hp应该还是初始值
//但是事实上观察到的是:
System.out.printf("%d个增加线程和%d个减少线程结束后%n盖伦的血量变成了 %.0f%n",
n,n,teemo.hp);
}
期望的观察结果应该是30000,但是实际运行结果是:

(注:如果观察的时30000,说明电脑性能比较好,继续增加线程数量和血量)
1. 假设增加线程先进入,得到的hp是30000
2. 进行增加运算
3. 正在做增加运算的时候,还没有来得及修改hp的值,减少线程来了
4. 减少线程得到的hp的值也是30000
5. 减少线程运算结束了,得到值30000,将该值赋给HP。
6. 增加线程运算结束,得到值30001,并把这个值赋予hp
hp,最后的值就是30001
虽然经历了两个线程各自增减了一次,本来期望还是原值30000,但是却得到了一个30001
这个时候的值30001是一个错误的值,在业务上又叫做脏数据。愿意是因为,减少线程还没来得及减少,增加线程就获得了数据30000。
解决思路:加锁,在增加线程访问hp期间,其他线程不可以访问hp
1. 增加线程获取到hp的值,并进行运算
2. 在运算期间,减少线程试图来获取hp的值,但是不被允许
3. 增加线程运算结束,并成功修改hp的值为30001
4. 减少线程,在增加线程做完后,才能访问hp的值,即30001
5. 减少线程运算,并得到新的值30000
使用synchronized关键字对资源进行独占,当线程独占了对象someobject,如果有其他线程试图占有someobject,就会发生等待,
直到当前线程释放对someObject的占用。someObject又称为同步对象,所有的对象,都可以作为同步对象。
浙公网安备 33010602011771号