day18_java多线程编程

线程

基本概念

进程:内存中正在进行的一个程序

线程:进程中的一个执行流程

多线程:有两个 或者 两个以上并发的执行流程

线程的生命周期,线程分为以下五种状态

  • (新建) New Thread();
  • (就绪) start();
  • (运行) run();
  • (阻塞) 暂停执行

    • sleep(就像我们做总结睡着了),join(让其他人先做,就像做总结时中间让其他人讲话)阻塞

      sleep:等待多少毫秒;超过了之后回复就绪状态等待cpu调用执行
      join:等待其他线程执行完,线程A调用了线程B的join();方法,那么线程A等线程B执行完再执行

    • 同步(排队)
    • wait(晕过去了)
  • (死亡)

线程图解:

这里写图片描述

主线程

当Java程序启动时,一个线程立刻运行,该线程通 常叫做程序的主线程(main thread),==它是程序 开始时就执行的==。

主方法就是主线程的任务 main();

public class TestThreadMain {

    public static void main(String[] args) {
        // 获得当前的线程                      主线程名字,优先级,主线程组
        System.out.println(Thread.currentThread());//Thread[main,5,main]
        System.out.println(Thread.currentThread().getName());//main


    }

}

问题:启动一个java应用程序至少启动几个主线程?

会先启动两个线程:一个主线程,一个垃圾回收线程

子线程

默认的名字:Thread —— 数字

创建子线程

  • 方式一:继承自Thread类
  • 方式二:实现Runnable 接口

区别
1. 继承Thread类,继承了Thread类的所有可以继承的;Runnable接口,只有run();
2. Runnable接口有利于资源共享

希望主线程最后结束

  1. sleep() 暂停多长时间
  2. isAlive() 判断线程仍在运行,isAlive()方法返回true,如果丌是则 返回false。
  3. join() 等待一个线程执行完

/** 创建子线程示例代码 */

//创建子线程方法一:继承自Thread类  
class MyThread extends Thread{
    MyThread(String name){
        super(name);
    }

    //子线程的任务功能在run中
    @Override
    public void run() {
        for(int i = 1; i<= 3 ; i++){
            System.out.println(Thread.currentThread().getName() +":"+i);
        }
    }

}


//创建子线程方法二:实现Runnable 接口    用的较多,有利于资源共享
class ThreadDemo implements Runnable{

    @Override
    public void run() {
        for(int i = 1; i<= 3 ; i++){
            System.out.println(Thread.currentThread().getName() +"吃饭");
        }

    }
}

public class TestThread1 {

    public static void main(String[] args) {
//      //创建一个线程对象
//      Thread t = new Thread();
//      //启动线程
//      t.start();

//      //创建一个子线程
//      MyThread t1 = new MyThread("t1");//新建
//      //启动子线程,必须用start,并且只能启动一次
//      t1.start();//就绪


        //不是线程对象
        ThreadDemo demo = new ThreadDemo();
        //                     绑定ThreadDemo类对象
        //Thread zhangsan = new Thread(demo);
        Thread zhangsan = new Thread(demo,"张三");
        Thread lisi = new Thread(demo,"李四");


        //设置优先级
        /*  lisi.setPriority(10);
        zhangsan.setPriority(1);*/
        //最低,普通,最高        比直接赋予数字好一些
        //1   5   10
        zhangsan.setPriority(Thread.MAX_PRIORITY);
        zhangsan.setPriority(Thread.MIN_PRIORITY);
        zhangsan.setPriority(Thread.NORM_PRIORITY);

        //启动线程
        zhangsan.start();
        lisi.start();

        //希望主线程最后结束方法一
    /*  try {
            Thread.sleep(1000);//等1000毫秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        ////希望主线程最后结束方法二:判断子线程是否运行
/*      if(zhangsan.isAlive() || lisi.isAlive()){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }*/

    //希望主线程最后结束方法三:让子线程都执行完才能恢复主线程
        try {
            zhangsan.join();
            lisi.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("主线程结束");


    }

}

线程优先级

1 – 10

10最高

  • 理论上,优先级高的线程比优先级低的线程获得更 多的CPU时间
  • 实际上,线程获得的CPU时间通常由包括优先级在 内的==多个因素==决定
  • 理论上,等优先级线程有同等的权利使用CPU
/** 创建子线程 */

//创建子线程方法一:继承自Thread类  
class MyThread extends Thread{
    MyThread(String name){
        super(name);
    }

    //子线程的任务功能在run中
    @Override
    public void run() {
        for(int i = 1; i<= 3 ; i++){
            System.out.println(Thread.currentThread().getName() +":"+i);
        }
    }

}

//创建子线程方法二:实现Runnable 接口    用的较多,有利于资源共享
class ThreadDemo implements Runnable{

    @Override
    public void run() {
        for(int i = 1; i<= 3 ; i++){
            System.out.println(Thread.currentThread().getName() +"吃饭");
        }

    }
}

public class TestThread1 {

    public static void main(String[] args) {
//      //创建一个线程对象
//      Thread t = new Thread();
//      //启动线程
//      t.start();

//      //创建一个子线程
//      MyThread t1 = new MyThread("t1");//新建
//      //启动子线程,必须用start,并且只能启动一次
//      t1.start();//就绪


        //不是线程对象
        ThreadDemo demo = new ThreadDemo();
        //                     绑定ThreadDemo类对象
        //Thread zhangsan = new Thread(demo);
        Thread zhangsan = new Thread(demo,"张三");
        Thread lisi = new Thread(demo,"李四");


        //设置优先级
        /*  lisi.setPriority(10);
        zhangsan.setPriority(1);*/
        //最低,普通,最高        比直接赋予数字好一些
        //1   5   10
        zhangsan.setPriority(Thread.MAX_PRIORITY);
        zhangsan.setPriority(Thread.MIN_PRIORITY);
        zhangsan.setPriority(Thread.NORM_PRIORITY);

        //启动线程
        zhangsan.start();
        lisi.start();

        //希望主线程最后结束方法一
    /*  try {
            Thread.sleep(1000);//等1000毫秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        ////希望主线程最后结束方法二:判断子线程是否运行
/*      if(zhangsan.isAlive() || lisi.isAlive()){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }*/

    ////希望主线程最后结束方法三:让子线程都执行完才能恢复主线程
        try {
            zhangsan.join();
            lisi.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("主线程结束");


    }

}

线程其它方法

interrupt()线程中断 :sleep()和join()

**问题:**java线程什么时候会引发InterruptedException ?

前提:当前线程处于sleep或者join时,被其他线程中断了,那么当前线程会进行异常处理

class ThreadDemo1 implements Runnable{

    @Override
    public void run() {
        for(int i = 1 ; i <=5 ; i++){
            System.out.println(Thread.currentThread().getName()+","+i);
            if(i == 3){ 
                try {
                    //Thread.sleep(1000);
                    Thread.currentThread().join();
                } catch (InterruptedException e) {
                    System.out.println("进入异常处理了");
                //  e.printStackTrace();
                }
            }
        }


    }

}

public class TestThreadInterrupt {

    public static void main(String[] args) {
        ThreadDemo1 demo1 = new ThreadDemo1();
        Thread t1 = new Thread(demo1);
        t1.start();
        //主线程调用了子线程t1的interrupt方法,子线程t1被中断进入异常处理
        t1.interrupt();

    }

}

yield() 线程让步 (了解即可,现在基本不用):

Thread.yield():不能完全保证线程让步

class ThreadDemo1 implements Runnable{

    @Override
    public void run() {
        for(int i = 1 ; i <=5 ; i++){
            System.out.println(Thread.currentThread().getName()+","+i);
            if(i == 3){ 
                try {
                    //Thread.sleep(1000);
                    Thread.currentThread().join();
                } catch (InterruptedException e) {
                    System.out.println("进入异常处理了");
                //  e.printStackTrace();
                }
            }
        }


    }

}

public class TestThreadInterrupt {

    public static void main(String[] args) {
        ThreadDemo1 demo1 = new ThreadDemo1();
        Thread t1 = new Thread(demo1);
        t1.start();
        //主线程调用了子线程t1的iterrupt方法,子线程t1被中断进入异常处理
        t1.interrupt();

    }

}

线程的同步

什么是同步

某一时刻 此资源 只能被一个线程独占。
线程同步的真实意思和字面意思恰好相反。线程同步的真实意思,其实是“排队”:几个线程之间要排队,一个一个对共享资源进行操作,而不是同时进行操作。

为什么使用同步

当两个或两个以上的线程需要共享资源,他们需要某种方法来确定资源在某一时刻仅被一个线程占用,达到此目的的过程叫做同步。(某一时刻资源只能被一个线程独占)

使用同步

  1. 同步代码块
    我们可以将对某个方法的调用放入一个synchronized块内
synchronized(对象){ 

 同步块; 

} 
  1. 同步方法,锁的是对象 this
synchronized  方法{   } 
/**同步示例代码*/
class Bank implements Runnable{
    int money = 0;
    //存钱
    //同步方法
    synchronized public void setMoney(){
        money += 100;//存100
        System.out.println(Thread.currentThread().getName() + "存了100,余额:" +money);
    }
    @Override
    public void run() {
        for(int i = 0 ; i < 3 ; i++){
            //同步锁
            //同步块
/*          synchronized(this){
            setMoney();
            }*/
            setMoney();
        }

    }

}
public class TestBank {

    public static void main(String[] args) {
        Bank bank = new Bank();
        Thread zhangsan = new Thread(bank,"zhangsan");
        Thread lisi = new Thread(bank,"lisi");
        zhangsan.start();
        lisi.start();
    }

}

Lock

优势

可以显示加锁,释放锁

获得锁:

当一个线程 访问此对象的 同步块 或 同步方法的时候,
申请同步锁,申请成功了,就获得了锁。在执行 同步块
和 同步方法的过程中,其它线程 进入 线程锁定池中处于
阻塞状态。只有 当前执行锁的线程 释放了锁 其它线程
才有 机会 获得CPU的调用执行。

释放锁:

1.同步方法或同步块中的 代码正常执行完了,就释放了;
2. 出现了未处理的 异常Exception和
Error时 ,释放锁;
3。 break,return语句,会结束方法或
代码块,那么会释放锁。
4. 执行了 wait()会释放锁。

语法:

try{  
    加锁lock 

}finally{   
    释放unLock 

}

lock作用

  1. 可以显示加锁和释放锁
  2. 提供了更多功能

死锁

  • 每个对象只有一个锁(lock)不之相关联
  • 实现同步是要很大的系统开销作为代价的,甚至可 能造成死锁,所以尽量避免无谓的同步控制
/**死锁示例代码 */
class Zhangsan{
    public void say(){
        System.out.println("你给我书,我就给你画");
    }
    public void get(){
        System.out.println("张三获得了书");
    }
}

class Lisi{
    public void say(){
        System.out.println("你给我画,我就给你书");
    }
    public void get(){
        System.out.println("李四获得了画");
    }
}
class LockDemo implements Runnable{
    static Zhangsan zhangsan = new Zhangsan();
    static Lisi lisi = new Lisi();
    boolean tag ;

    @Override
    public void run() {
        if(tag == true){//张三
            synchronized(zhangsan){
            zhangsan.say();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            synchronized(lisi){
                zhangsan.get();
            }
            }
        }else{//李四
            synchronized(lisi){
                lisi.say();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                synchronized(zhangsan){
                    lisi.get();
                }
            }
        }

    }

}
public class Testlock {

    public static void main(String[] args) {
        LockDemo demo1 = new LockDemo();
        demo1.tag = true;
        LockDemo demo2 = new LockDemo();
        demo2.tag = false;
        Thread t1 = new Thread(demo1);
        Thread t2 = new Thread(demo2);
        t1.start();
        t2.start();
    }

}

wait()和sleep的区别:

  • 区别:
  • 时间参数
    • wait()可以可定时间也可以丌指定; sleep()必须指定时间;
  • 同步状态
    • sleep()释放执行权,不释放锁 ;wait释放执行权,释放锁
class Show implements Runnable{
    int i = 10 ;
    @Override
    synchronized public void run() {
        for(; i >= 0 ; i--){

            if(i == 5  && Thread.currentThread().getName().equals("t1:")){
                try {
                    //Thread.sleep(100000);
                    wait(1000);
                    System.out.println("我醒了");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+i);
        }   

    }

}

public class Exercise1 {

    public static void main(String[] args) {
        Show sh = new Show();
        Thread t1 = new Thread(sh,"t1:");
        Thread t2 = new Thread(sh,"t2:");
        t1.start();
        t2.start();

    }

}

包子铺实例理解wait()、notify()

package day26;
class QingFeng {
    private int count;//包子数量
    private boolean tag = false;//true ->有包子,false->没包子

    public int getCount() {
        return count;
    }
    public void setCount(int count) {
        this.count = count;
    }

    //生产包子
    synchronized public void put(int count){
        //有包子,休息
        if(tag == true){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //没有包子 false
        this.count = count;
        System.out.println("生产了" +this.count);
        tag = true;
        notify();//唤醒销售
    }
    //销售包子
    synchronized public void get(){
        //没包子可卖,休息一会
        if(tag == false){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 有包子true
        System.out.println("卖了" +this.count);
        tag = false;//卖完了
        notify();//唤醒厨师
    }

}
//生产
class Producer implements Runnable{
    QingFeng qingfeng;


    public Producer(QingFeng qingfeng) {
        super();
        this.qingfeng = qingfeng;
    }


    public Producer() {
        super();
    }


    @Override
    public void run() {
        //生产
        for(int i = 1 ; i <=5 ; i++){
            qingfeng.put(i);
        }
    }

}

//销售
class Consumer implements Runnable{
    QingFeng qingfeng;

    public Consumer() {
        super();
    }

    public Consumer(QingFeng qingfeng) {
        super();
        this.qingfeng = qingfeng;
    }

    @Override
    public void run() {
        for(int i = 1 ; i <= 5 ; i++){
            qingfeng.get();
        }
    }

}

public class Exercise2 {

    public static void main(String[] args) {
        QingFeng qingfeng = new QingFeng();
        Producer pro = new Producer(qingfeng);
        Consumer con = new Consumer(qingfeng) ;
        Thread t1 = new Thread(pro);
        Thread t2 = new Thread(con);
        t1.start();
        t2.start();

    }

}

猜你喜欢

转载自blog.csdn.net/qq_24135817/article/details/80557765