葵恩的学习笔记

导航

多线程

一、多线程实现

有三种实现多线程的方式:

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又称为同步对象,所有的对象,都可以作为同步对象。

 

posted on 2021-02-05 11:42  葵恩  阅读(51)  评论(0)    收藏  举报