多线程(一)

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);
        }
    }
}
KillThread.java
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();
         
    }
     
}
TestThread

 

二.实现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);
        }
    }
}
Battle.java
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();
 
    }
     
}
TestThread

 

三.匿名类

使用匿名类,继承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();
         
    }
      
}
TestThread.java

 

四.常见线程方法:链接

 

五.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();
    }
       
}
TestThread.java
17:00:34 t2 线程已经运行
17:00:34 t1 线程已经运行
17:00:34 t2 试图占有对象:someObject
17:00:34 t1 试图占有对象:someObject
17:00:34 t2 占有对象:someObject
17:00:39 t2 释放对象:someObject
17:00:39 t2 线程结束
17:00:39 t1 占有对象:someObject
17:00:44 t1 释放对象:someObject
17: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;   
        }
    }

 

posted @ 2019-04-14 16:28  Johnny、  阅读(127)  评论(0编辑  收藏  举报