java--多线程

java---多线程

一、线程简介
    线程:程序可执行的路径,或者说程序可执行的通道
    进程:一个个单独执行的程序或软件
    进程和线程的关系:线程是进程执行的路径、通道,多线程即有多个路径执行这个程序
    一个进程如果只有一个线程,那么这是个单线程程序,如果有多条线程,则为多线程程序
二、生命周期


    java--多线程_第1张图片 
创建多线程的方法:继承Thead父类和实现Runable接口

1、继承Thead
public class TheadDemo extends Thead{
       public void run()
       puclic static void main(String[] args){}
}

public class TheadDemo1 extends Thread {
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
public static void main(String[] args){
TheadDemo1 theadDemo1 = new TheadDemo1();
TheadDemo1 theadDemo2 = new TheadDemo1();
theadDemo1.start();
theadDemo2.start();
}


2、实现Runable接口
public class TheadDemo Implements Runable{
       puclic void run()
       puclic static void main(String[] args){}
}

      public class RunableDemo implements Runnable {
             @Override
                public void run() {
                         for(int i=0;i<100;i++){
                         System.out.println(Thread.currentThread().getName()+""+i);                           //   Thread.currentThread()  获得当前执行线程的信息      getName()   得到线程的名字
                   }
          }
               public static void main(String[] args){
                          RunableDemo runableDemo = new RunableDemo();
                         RunableDemo runableDemo1 = new RunableDemo();
                          Thread thread = new Thread(runableDemo,"线程一");                                           //new Thead(  要创建线程的类对象, 给线程起的名字);
                         Thread thread1 = new Thread(runableDemo1, "线程二");
                         thread.start();
                        thread1.start();
          }

    }
run()方法:当一个线程启动后,就会自动去执行这个方法,当有多个线程的时候每个线程都会去调用run()方法,多个线程是没有执行顺序的,是由cpu随机分配,多个线程依次执行。main()方法主线程是不会去调用外部的run()方法的

两种实现接口方法的区别:

   Thead:

           优点:使用方便          缺点:单继承的局限性

    Runable:

            优点:可以多继承       缺点:使用麻烦

 

 

三、常用的方法:

     setPriority(int  new Priority):更改线程的优先级,默认值是5,范围是1-10。1的优先级最低,10的优先级最高

     join():插入:在当前的线程执行中,如果使用join()插入一个线程,那么就会先执行插入的线程,并且要执行完毕才会再执行原来的线程

     sleep(long millis):设置线程休眠,时间以毫秒为单位。设置线程在指定的时间内休眠,不运行。

     yield()暂停正在运行的线程,礼让执行:该方法就像公交车上的让座,被让座的可能接收也可能不接受,所以线程既可能执行原来的也可能执行插入进来的线程

案例:

      slepp和setPriority:

java--多线程_第2张图片

 

  join():

     public class JoinDemo implements Runnable {
           @Override
            public void run() {
                   for(int i=0;i<10;i++){
                    System.out.println(Thread.currentThread().getName()+" "+i);
                   }
            }
             public static void main(String[] args) throws InterruptedException {
                  JoinDemo joinDemo = new JoinDemo();
                  Thread thread = new Thread(joinDemo);
                  thread.start();
                   for(int i=0;i<10;i++){
                  System.out.println(Thread.currentThread().getName());
                   if(i==3){
                      //join() 插队执行
                  thread.join();
                        //yield() 礼让执行,可能礼让成功,也可能失败
                        //Thread.yield();
                      }
                      }
             }
       }

 四、同步锁

       当多个线程操作同一共享资源时,将引发数据不安全问题,如下:利用线程休眠来模拟网络延迟,多个线程去一家商店买裤子

    public class BuyGoodsDemo implements Runnable {
           private int num=10; //裤子总数
           private int count=0;//购买到的是第几条裤子
          @Override
           public void run() {
                    //每一个人买过之后,num减一,count加一
                 while(true){
                       if(num<=0){
                            //裤子卖完,跳出循环
                             break;
                            }
                         num--;
                         count++;
                           try{
                                   //模拟网络延迟
                                    Thread.sleep(100);
                                }catch (InterruptedException e){
                                    e.printStackTrace();
                                 }
                             System.out.println(Thread.currentThread().getName()+"买到的是第"+count+"条裤子,还有"+num+"条");
                    }
            }
            public static void main(String[] args){
                    BuyGoodsDemo buyGoodsDemo = new BuyGoodsDemo();
                    Thread t1 = new Thread(buyGoodsDemo, "小敏");
                    Thread t2 = new Thread(buyGoodsDemo, "小青");
                     Thread t3 = new Thread(buyGoodsDemo, "小红");
                     Thread t4 = new Thread(buyGoodsDemo, "小白");
                     t1.start();
                        t2.start();
                     t3.start();
                      t4.start();
                     }
       }

执行后的结果:

 

原因:这时因为当一个线程执行run()方法后,num和count被操作,但是再往后执行就出现了网络延迟,第一个执行的线程还有执行完毕,后边的线程已经将num和count执行了,当网络恢复了,

          第一个线程再向下执行,此时的每个参数数值已经是最后一个线程执行后的参数数值

 解决方法:synchronized:同步锁,将容易出现问题的代码进行包裹,包裹后就成了单线程。

 两种写法:同步代码块和同步方法

第一种:同步代码块:

public class BuyGoodsDemo1 implements Runnable {
/**
* synchronized:同步锁,将容易出现问题的代码进行包裹,包裹后就成为了单线程
* 一、同步代码块(该例中用同步代码块)
* 二、同步方法
* */
private int num=10;
private int count=0;//购买到的是第几条裤子
@Override
public void run() {
//每一个人买过之后,num减一,count加一
while(true){

          //...........................................................................................................................
                  synchronized (this){
                        if(num<=0){
                     //裤子卖完,跳出循环
                           break;
                      }
                      num--;
                       count++;
                       System.out.println(Thread.currentThread().getName()+"买到的是第"+count+"条裤子,还有"+num+"条");
                      }

          //...............................................................................................................................
try{
//模拟网络延迟
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}

}

}
public static void main(String[] args){
BuyGoodsDemo1 buyGoodsDemo = new BuyGoodsDemo1();
Thread t1 = new Thread(buyGoodsDemo, "小敏");
Thread t2 = new Thread(buyGoodsDemo, "小青");
Thread t3 = new Thread(buyGoodsDemo, "小红");
Thread t4 = new Thread(buyGoodsDemo, "小白");
t1.start();
t2.start();
t3.start();
t4.start();
}
}

      第二种:同步方法

public class BuyGoodsDemo2 implements Runnable {
/**
* synchronized:同步锁,将容易出现问题的代码进行包裹,包裹后就成为了单线程
* 一、同步代码块
* 二、同步方法(该例中用同步方法)
* */
private int num=10;
private int count=0;//购买到的是第几条裤子
@Override
public void run() {
//每一个人买过之后,num减一,count加一
while(true){

if(!buy()){
break;
}

try{
//模拟网络延迟
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}

}

}
public synchronized boolean buy(){
if(num<=0){
//裤子卖完,跳出循环
return false;
}
num--;
count++;
System.out.println(Thread.currentThread().getName()+"买到的是第"+count+"条裤子,还有"+num+"条");
return true;
}
public static void main(String[] args){
BuyGoodsDemo2 buyGoodsDemo = new BuyGoodsDemo2();
Thread t1 = new Thread(buyGoodsDemo, "小敏");
Thread t2 = new Thread(buyGoodsDemo, "小青");
Thread t3 = new Thread(buyGoodsDemo, "小红");
Thread t4 = new Thread(buyGoodsDemo, "小白");
t1.start();
t2.start();
t3.start();
t4.start();
}
}








练习:

一、 使用多线程模拟年轻人与老人年徒步爬到1500米的山顶

 
 

需求讲解:

 
 

年轻人每爬100米需要300毫秒,

 
 

老人年爬完100米需要1000毫秒,

 
 

利用线程的休眠分别模拟老年人与年轻人每爬100米需要的时间,实现该案例。

 

二、 利用多线程模拟叫号看病

需求讲解:

1、某科室一天需看普通号50个,特需号10

2、特需号看病时间是普通号的2倍(设置线程的休眠)

3、开始时普通号和特需号并行叫号(两个线程同时分别被调度),叫到特需号的概率比普通号高(设置线程的优先级)

4、当普通号叫完第10号时,要求先看完全部特需号,再看普通号(join方法)

使用多线程模拟这一过程,执行效果大致如下:

 

代码:第一题:
public class HomeWorkThead implements Runnable {
@Override
public void run() {
for(int i=0;i<10;i++){
try {
Thread.sleep(3000);//设置vip号的诊断时间
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+i);
}

}
public static void main(String[] args){
HomeWorkThead homeWorkThead = new HomeWorkThead();
Thread thread = new Thread(homeWorkThead,"vip号");
//设置主线程为普通号
Thread.currentThread().setName("普通号");
thread.setPriority(10);//设置vip号的优先级
thread.start();
for(int i=0;i<50;i++){
System.out.println(Thread.currentThread().getName()+i);
if(i==10){
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}
}
}


第二题代码:
public class HomeWorkThead2 implements Runnable {
@Override
public void run() {
if(Thread.currentThread().getName().equals("年轻人")) {
for (int i = 0; i < 15; i++) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "跑完一百米");
if(i==14){
System.out.println(Thread.currentThread().getName()+"跑完了");
}
}
}
if(Thread.currentThread().getName().equals("老年人")){for (int i = 0; i < 15; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "跑完一百米");
if(i==14){
System.out.println(Thread.currentThread().getName()+"跑完了");
}
}}
}
public static void main(String[] args){
HomeWorkThead2 h1 = new HomeWorkThead2();
HomeWorkThead2 h2 = new HomeWorkThead2();

Thread t1 = new Thread(h1, "年轻人");
Thread t2 = new Thread(h2, "老年人");

t1.start();
t2.start();
}
}
 


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