java 多线程

进程的概念:

  进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。例如在Windows系统中,一个运行的exe就是一个进程。

线程的概念:

  线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。

一、Java中的线程

  Java编写程序都运行在在Java虚拟机(JVM)中,在JVM的内部,程序的多任务是通过线程来实现的。每用java命令启动一个java应用程序,就会启动一个JVM进程。在同一个JVM进程中,有且只有一个进程,就是它自己。在这个JVM环境中,所有程序代码的运行都是以线程来运行。每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记为一个守护程序。当某个线程中运行的代码创建一个新Thread对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。同时JVM也负责线程的调度。线程调度是值按照特定的机制为多个线程分配CPU的使用权。调度的模式有两种:分时调度和抢占式调度。分时调度是所有线程轮流获得CPU使用权,并平均分配每个线程占用CPU的时间;抢占式调度是根据线程的优先级别来获取CPU的使用权。JVM的线程调度模式采用了抢占式模式。

  1.多线程实现方式一      继承 Thread类

 

public class TestThread1 extends Thread {

    public void run() {

        for(int i=0;i<10;i++){

            System.out.println("TestThread1=======>"+i);

        }

    }

}

class TestThread2 extends Thread{

    public void run() {

        for(int i=0;i<10;i++){

            System.out.println("TestThread2========>"+i);

        }

    }

}

//测试

public static void main(String[] args) {

    TestThread1 th1=new TestThread1();

    TestThread2 th2=new TestThread2();

    th1.start();

    th2.start();

}

//结果

TestThread1=======>0

TestThread2========>0

TestThread1=======>1

TestThread2========>1

TestThread1=======>2

TestThread2========>2

TestThread1=======>3

TestThread2========>3

TestThread1=======>4

TestThread2========>4

TestThread1=======>5

TestThread2========>5

TestThread1=======>6

TestThread2========>6

TestThread1=======>7

TestThread2========>7

TestThread1=======>8

TestThread2========>8

TestThread1=======>9

TestThread2========>9
View Code

 2、实现   Runnable 接口 (静态代理模式)

public class RunnableTest1 implements Runnable{

    public void run() {

        for(int i=0;i<10;i++){

            System.out.println("RunnableTest1==============>"+i);

        }

    }

}

class RunnableTest2 implements Runnable {

    public void run() {

        for(int i=0;i<10;i++){

            System.out.println("RunnableTest2==============>"+i);

        }

    }

}

//测试

public static void main(String[] args) {

        //创建真实角色

        RunnableTest1 rt1=new RunnableTest1();

        RunnableTest2 rt2=new RunnableTest2();

        //创建代理角色+真实角色的引用

        Thread thread1=new Thread(rt1);

        Thread thread2=new Thread(rt2);

        //启动

        thread1.start();

        thread2.start();

    }

//结果

    

RunnableTest1==============>0

RunnableTest1==============>1

RunnableTest2==============>0

RunnableTest1==============>2

RunnableTest1==============>3

RunnableTest1==============>4

RunnableTest2==============>1

RunnableTest1==============>5

RunnableTest2==============>2

RunnableTest1==============>6

RunnableTest1==============>7

RunnableTest2==============>3

RunnableTest1==============>8

RunnableTest2==============>4

RunnableTest1==============>9

RunnableTest2==============>5

RunnableTest2==============>6

RunnableTest2==============>7

RunnableTest2==============>8

RunnableTest2==============>9
View Code

  两种实现方式的区别和联系:

    在程序开发中只要是多线程肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:

  • 避免点继承的局限,一个类可以继承多个接口。
  • 适合于资源的共享 
 1 //资源共享

 2 public class TrainTest implements Runnable {

 3     private int num=5;

 4     public void run() {

 5         while(true){

 6             if(num<=0){

 7                 break;

 8             }

 9             System.out.println(Thread.currentThread().getName()+"抢到第"+num--+"张票");

10         }

11     }

12     public static void main(String[] args) {

13         TrainTest tt=new TrainTest();

14         Thread t1=new Thread(tt, "NNNN");

15         Thread t2=new Thread(tt, "AAAA");

16         Thread t3=new Thread(tt, "MMMMM");

17         t1.start();

18         t2.start();

19         t3.start();

20     }

21 }

22 MMMMM抢到第5张票

23 NNNN抢到第4张票

24 AAAA抢到第3张票

25 NNNN抢到第1张票

26 MMMMM抢到第2张票
View Code

   3、使用  Callable 接口

          常用的Thread类在run方法执行完之后是没有返回值的,要实现子线程完成任务后返回值给主线程需要借助第三方转存。

  Callable接口则提供了一种有返回值的多线程实现方法。

  

package com.jalja.jdk17.thread;



import java.util.concurrent.Callable;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;



public class CallableTest implements Callable<Integer> {

    private String name;//名称

    private long time;//延时时间

    private boolean flag=true;

    private int step=0;//

    public CallableTest() {

        super();

    }

    public CallableTest(String name) {

        super();

        this.name = name;

    }

    public CallableTest(String name, long time) {

        super();

        this.name = name;

        this.time = time;

    }

    public Integer call() throws Exception {

        while(flag){

            Thread.sleep(time);//延时 走的快慢

            step++;

        }

        return step;

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public long getTime() {

        return time;

    }

    public void setTime(long time) {

        this.time = time;

    }

    public boolean isFlag() {

        return flag;

    }

    public void setFlag(boolean flag) {

        this.flag = flag;

    }

    public int getStep() {

        return step;

    }

    public void setStep(int step) {

        this.step = step;

    }

    public static void main(String[] args) throws Exception{

        //创建线程

        ExecutorService es=Executors.newFixedThreadPool(2);

        CallableTest ct1=new CallableTest("乌龟",100);

        CallableTest ct2=new CallableTest("兔子",50);

        //获取值

        Future<Integer>result1=es.submit(ct1);

        Future<Integer>result2=es.submit(ct2);

        Thread.sleep(2000);

        ct1.setFlag(false);

        ct2.setFlag(false);

        int num1=result1.get();

        int num2=result2.get();

        System.out.println("乌龟跑---->"+num1+"步");

        System.out.println("兔子跑---->"+num2+"步");

        //停止服务

        es.shutdown();

    }

}

//结果

乌龟跑---->20步

兔子跑---->40步
View Code

4、线程的终止

  停止线程的方式:
  1) 自然终止:线程体正常执行完毕
  2) 外部干涉:

          a.定义线程体使用标识

      b.在线程体中使用标识

   c.提供对外改变标识的方法

    d.外部根据条件调用 该方法

  

//2外部干涉

public class ThreadColse implements Runnable {

        // 定义线程体使用标识

    private boolean flag=true;

    public void run() {

    //在线程体中使用标识

        while(flag){

            System.out.println("执行------》");

        }

    }

      //提供对外改变标识的方法

    public  void stop(){

       flag=false;

    }

    public static void main(String[] args) {

        ThreadColse tc=new ThreadColse();

        new Thread(tc).start();

        //外部根据条件调用 该方法

        for(int i=0;i<20;i++){

            if(i==10){

                tc.stop();

            }

            System.out.println("运行了——————————》"+i);

        }

    }

}
View Code

 二、线程的状态

  java 多线程

  1、创建状态。在生成线程对象,并没有调用该对象的start方法。

  2、就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时cpu并没有调度它。

  3、运行状态。线程调度程序将处于就绪状态的线程设置为当前线程(cpu调度该线程),此时线程就进入了运行状态,开始运行run函数当中的代码。

  4、阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。

    a.join 合并线程   b、yield() 暂停自己的线程    c、 sleep() 线程进入休眠    不释放锁

  5、死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪。

三、线程同步

      为什么需要同步

              当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),  将会导致数据不准确,相互之间产生冲突。
  
public class TrainTest implements Runnable {

    private int num=5;

    public void run() {

        while(true){

            if(num<=0){

                break;

            }

            try {

                new Thread().sleep(500);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println(Thread.currentThread().getName()+"抢到第"+num--+"张票");

        }

    }

    public static void main(String[] args) {

        TrainTest tt=new TrainTest();

        Thread t1=new Thread(tt, "NNNN");

        Thread t2=new Thread(tt, "AAAA");

        Thread t3=new Thread(tt, "MMMMM");

        t1.start();

        t2.start();

        t3.start();

    }

}

NNNN抢到第4张票

AAAA抢到第5张票

MMMMM抢到第3张票

NNNN抢到第2张票

AAAA抢到第1张票

MMMMM抢到第0张票

出现了 第0张票  这样就出现了资源错误的现象
View Code

   同步方法 

            使用 synchronized      

public class TrainTest implements Runnable {

    private int num=5;

    private boolean flag=true;

    public void run() {

        while(flag){

            test();

        }

    }

    private synchronized void test(){

        if(num<=0){

            flag=false;

            return;

        }

        try {

            new Thread().sleep(500);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        System.out.println(Thread.currentThread().getName()+"抢到第"+num--+"张票");

     }    

    public static void main(String[] args) {

        TrainTest tt=new TrainTest();

        Thread t1=new Thread(tt, "NNNN");

        Thread t2=new Thread(tt, "AAAA");

        Thread t3=new Thread(tt, "MMMMM");

        t1.start();

        t2.start();

        t3.start();

    }

}

NNNN抢到第5张票

NNNN抢到第4张票

NNNN抢到第3张票

NNNN抢到第2张票

NNNN抢到第1张票

  



这样 就没有 出现第 0张票 的现象了, 但观察程序会发现运行速度慢了很多,因为线程出现等待的现象

 
View Code

 线程的死锁:

             死锁的原因是由于 两个线程相互等待 对方已被锁定的资源

package com.jalja.jdk17.thread;

//过多的同步方法 会 造成死锁

public class SSTest {

    public static void main(String[] args) {

        Object g=new Object();

        Object m=new Object();

        Test01 t1=new Test01(g,m);

        Test02 t2=new Test02(g,m);

        Thread th1=new Thread(t1);

        Thread th2=new Thread(t2);

        th1.start();

        th2.start();

    }

}

class Test01 implements Runnable{

    Object goods;

    Object money;

    public Test01(Object goods, Object money) {

        super();

        this.goods = goods;

        this.money = money;

    }

    private void test(){

        synchronized (goods) {

            try {

                Thread.sleep(200);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        synchronized (money) {

            

         }    

        }

        System.out.println("一手给货");

    }

    public void run() {

        while(true){

            test();

        }

    }

}

class Test02 implements Runnable{

    Object goods;

    Object money;

    public Test02(Object goods, Object money) {

        super();

        this.goods = goods;

        this.money = money;

    }

    private void test(){

        synchronized (money) {

            try {

                Thread.sleep(200);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        synchronized (goods) {

            

         }    

        }

        System.out.println("一手给钱");

    }

    public void run() {

        while(true){

            test();

        }

    }

}
View Code

   解决死锁问题

package com.jalja.jdk17.Polymorphic;

/**

 * 解决死锁的方式 

 * 生产者消费着模式  信号灯法

 * @author Administrator

 *

 */

public class Movies {

    private String pic;

    // true :生产者     生产,消费者等待,生产完毕后通知消费者消费

    //false:消费者 消费 生产者等待,消费者完成消费后通知生产

    private boolean flag=true;

    public synchronized void play(String pic){

        if(!flag){

            try {

                this.wait();//等待   释放锁

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

           //开始生产

            try {

                Thread.sleep(500);//模拟生产耗时500毫秒

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            this.pic=pic;//生产出资源

            System.out.println("生产=======》"+pic);

            //通知消费者消费

            this.notify();

            //生产者停止生产

            this.flag=false;

    }

    public synchronized void watch(){

        if(flag){//消费者等待

            try {

                this.wait();//等待   释放锁

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

        //开始消费

        try {

            Thread.sleep(500);//模拟消费耗时500毫秒

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        this.pic=pic;//消费资源

        System.out.println("消费=======》"+pic);

        //通知生产

        this.notifyAll();

        //消费者停止消费

        this.flag=true;

    }

}

package com.jalja.jdk17.Polymorphic;



public class Player implements Runnable {

    private Movies movies;

    

    public Player(Movies movies) {

        super();

        this.movies = movies;

    }

    public void run() {

        for(int i=0;i<5;i++){

            if(i%2==0){

                movies.play("《无间道》");

            }else{

                movies.play("《道道道道道道》");

            }

        }

        

    }



}

package com.jalja.jdk17.Polymorphic;



public class Watcher implements Runnable {

    private Movies movies;

    

    public Watcher(Movies movies) {

        super();

        this.movies = movies;

    }

    public void run() {

        for(int i=0;i<5;i++){

          movies.watch();

        }

    }

    public static void main(String[] args) {

        Movies m=new Movies();

        Player p=new Player(m);

        Watcher w=new Watcher(m);

        Thread th1=new Thread(p);

        Thread th2=new Thread(w);

        th1.start();

        th2.start();

    }

}

//结果

生产=======》《无间道》

消费=======》《无间道》

生产=======》《道道道道道道》

消费=======》《道道道道道道》

生产=======》《无间道》

消费=======》《无间道》

生产=======》《道道道道道道》

消费=======》《道道道道道道》

生产=======》《无间道》

消费=======》《无间道》
View Code

 

  

你可能感兴趣的:(java 多线程)