【JAVA基础】基础差学习JAVA第四天——多线程

快捷键:ALT+enter 创建对象

参数列表·ctr P

查看构造器:ctrl o

一、多线程

1.概念

单线程:就是一条线内能执行的程序

每一份线程有单独的:虚拟机栈 和程序计数器

多个线程共享:方法区和堆 一个进程一份,

2.单核CPU:

只能执行一个线程

多核CPU:

java应用程序java.exe,至少有三个线程:main()主线程,gc()垃圾回收站,异常处理线程

注意:

单核CPU下, 只使用单个线程先后完成多个任务,比多个线程完成用的时间短

3.并行与并发

并行:多个CPU同时执行多个任务,不同人做不同事

并发:一个CPU同时执行多个任务

4.关于线程的8个方法

/**1.Thread.currentThread():静态方法 返回执行当前代码的线程
 * 2.getName():获取当前线程的名字  ①构造器命名public thread(String name){}②通过当前对象命名
 * 3.setName():设置当前线程的名字
 * 4.yield():释放当前执行得线程,给别的线程用
 * 5.join():在线程a中调用线程b的join(),此时线程a进入阻塞状态,直到join()的线程完全执行完以后,线程a才能继续执行
 * 6.stop():过时 强制结束当前线程
 * 7.sleep(long millitime): 让当前线程睡眠指定几毫秒 抛异常
 * 8.isAlive():判断当前线程是否存活

5.线程的调用

时间片

抢占式:高优先级的线程抢占CPU

6.线程的优先级

线程的优先级  不一定实施
 MAX_PRIORITY   优先级10
 NORM_PRIORITY     5
 MIN_PRIORITY      1

创建多线程的方式

一、继承Thread()

  • 当前类继承Thread类
  • 再启动一个线程,必须创建一个新的Thread子类的对象H1,调用此对象的start()
1.创建一个继承于Thread类的子类
 * 2.重写Thread类的run  将此线程执行的内容声明在run()方法中
 * 3.创建Thread类子类的对象  主线程
 * 4.通过此对象调用start()方法
 *
  // 编译100以内的偶数
class  HelloThread extends Thread{   	//1.
    public void run() {					//2.
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
     System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()+ ":" + i);
            }
        }
    }
    public HelloThread(String name){        //有参构造器 
        super(name);
    }
}


public class ThreadMethodTest {        			   public static void main(String[] args) {     		//分线程  	HelloThread H1=new HelloThread("Thread:1");   //3.方式一 有参构造器
       H1.setPriority(Thread.MAX_PRIORITY);     //最小值10
       H1.start();								//4.
       Thread.currentThread().setName("主线程");  //主线程   Thread.currentThread().setPriority(Thread.MIN_PRIORITY);    // 1
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
        System.out.println(Thread.currentThread().getName()+Thread.currentThread().getPriority()+ ":" + i);
            }
        }
    }
}

二、实现runnable接口

1.创建一个实现了runnable接口的类
2.类去实现runnable接中的抽象方法
3.创建实现类的对象
4.将此对象作为参数传递到Thread类中的构造器中,创建thread类的对象  多态
5.通过thread类的对象调用start()

源码:

class Mthread implements Runnable{   //继承于object
    public void run(){
        for(int i=0;i<100;i++){
            if(i%2==0){
            System.out.println(i);
        }
    }
}
public static class ThreadTest1 {
    public static void main(String[] args) {
        Mthread Mthread1=new Mthread(); //创建当前类的对象
        Thread t1=new Thread( Mthread1);  
//对象作为参数传递到Thread类中的构造器中,创建thread类的对象 多态
        t1.start();
  //②调用了当前线程的run() 调用了private runnable target
    }
  }
}

问题:创建线程,继承和接口如何选择

优先选择实现Runnable接口

继承父类

共享数据

7.线程的生命周期

在这里插入图片描述

①新建:一个thread类或子类对象被声明创建时,新生的线程对象处于新建的状态

②就绪:新建状态被start()后,进入线程队列等待CPU时间片

③阻塞:被人挂起或执行输入输出操作时,让出CPU并临时中止自己的执行(sleep(long time),join,wait(),suspend() )

④运行:线程被调度,run()方法定义了线程的功能(运行就绪可反复执行)

⑤死亡:完成了全部工作或线程提前强制性中止或出现异常导致结束(执行完run()、stop、Error、Exception)

线程的同步 /线程的安全问题

线程的安全问题:例如,一个线程执行卖票过程中未完成,另一个线程也参与进来,操作卖票

同步机制:

一、同步代码块

  1. 可以继承Thread类
  2. 可以实现Runnable接口

二、同步方法

操作的共享数据的代码完整的声明在一个方法中,我们将此方法声明为同步的

​ 3.也可以继承Thread类

​ 4.也可以实现Runnable接口

在继承下,每个对象都有属性,如果要共享,给属性加上static

static Object obj=new Object();  //设置为静态对象 共用同一把锁

继承Thread类
同步方法的同步监视器 不需要显示的声明
非静态的方法 同步监视器是this
非静态的同步方法:同步监视器是当前类本身

**线程安全问题
 * 一、同步代码块解决Runnable接口线程安全
 * synchronized(同步监视器){
 *     被同步的代码,即操作共享数据的代码
 * }

 * 说明:
 * 共享数据:多个线程共同操作的变量 例如 ticket
 * 同步监视器:即锁 任何一个类的对象都可以充当锁  多个线程共用一把锁!!
 * 相当于单线程
//三个线程共用100张票
//方法一 :同步代码块  解决Runnable接口线程安全
class window1 implements Runnable{
    private int ticket=100;   //三个线程共用100张票
    Person p1=new Person();
    public void run(){
        while(true){
            synchronized (p1){              //包住和ticket相关的代码块
            if(ticket>0){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"卖票"+ticket);
                ticket--;
            }else{
                break;
              }
            }
        }
    }
}
public class WindowTest1 {
    public static void main(String[] args) {
        window1 w1=new window1();
        Thread t1=new Thread(w1);  //多态 父类为thread
        Thread t2=new Thread(w1);
        Thread t3=new Thread(w1);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}
class Person{ }  //定义在其他类

补充:

  • 在实现Runnbale接口时创建多线程的方式中,考虑使用this充当同步监视器

  • 继承Thread类创建多线程,慎用this充当同步监视器,用当前类作为同步监视器

//方法二  同步方法  实现runnbale接口
 操作的共享数据的代码完整的声明在一个方法中,我们将此方法声明为同步的
class window3 implements Runnable{
    private int ticket=100;             //三个线程共用100张票

    public void run(){
        while(true){
                show();
                }
        }
    public synchronized void show(){    
        //同步监视器:this
        if(ticket>0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println(Thread.currentThread().getName() + "卖票" + ticket);
                ticket--;
            }}}}
public class WindowTest3 {
    public static void main(String[] args) {
        window1 w1=new window1();
        Thread t1=new Thread(w1);               //多态
        Thread t2=new Thread(w1);
        Thread t3=new Thread(w1);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

三、!Lock锁

JDK5.0新增

  1. *Lock锁:*显示锁手动提供同步(lock()),手动解锁
  2. *synchronized():*隐式锁 自动释放同步监视器
class Window implements Runnable {
    private int ticket=100;
    private ReentrantLock lock=new ReentrantLock(true);   //创建锁对象

    public void run(){
        while(true){
            try{
                lock.lock();  //调用锁定方法
                if(ticket>0){
                    try{
                        Thread.sleep(100);
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
	System.out.println(Thread.currentThread().getName()+"卖票窗口为"+ticket);
                    ticket--;
                }else {
                    break;
                }
            }finally{    //一定会执行的代码
                lock.unlock();  //调用解锁方法
            }
        }
    }
}
public class LockTest {
    public static void main(String[] args) {
        Window w=new Window();

        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

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

四种方式使用的优先顺序

Lock锁------>同步代码块-------->同步方法(在方法体之外)

10.死锁:

不同线程分别占用对方所需的资源不放手,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁,所有线程处于阻塞状态

一个先A后B 一个先B后A

11.线程的通信:

wait():执行后阻塞,当前线程进入阻塞状态,并释放同步监视器

notify():(唤醒)一旦执行此方法后,就会唤醒优先级高的一个线程,

notifyAll():唤醒所有被wait的线程

三个方法的调用者是同步代码块或同步方法中的同步监视器,否则会出现IllegalMonitorStateException异常

三个方法在Java.lang.Object中

//线程通信   线程1 线程2交替打印 1-100
class Number implements Runnable{
    private int number=1;
    public void run(){
        while(true){
            synchronized(this){                    //同步监视器 任何一个类的对象可以充当
                notify();    					//线程2 唤醒线程1
                if(number<=100){
                    System.out.println(Thread.currentThread().getName()+":"+number);
                    number++;
                    try {
                        wait();               //阻塞一下!抛异常 线程2执行完wait后释放同步监视器
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
public class Communicate {
    public static void main(String[] args) {
        Number n1=new Number();             //创建当前类的对象
        
        Thread t1 = new Thread(n1);//多态 父类给子类
        Thread t2 = new Thread(n1);
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
    }
}
sleep()和wait()的异同

都导致进入阻塞

不同:

  1. 声明位置不同:Thread类中声明sleep(),Object中声明wait()
  2. wait()在同步代码块或同步方法中使用
  3. 是否释放同步监视器 :sleep()不会释放锁 ,wait()会释放锁

三、Callable接口 JDK5.0

如何理解Callable接口与Runnable接口创建线程方式强大

  1. 与run()方法相比,可以有返回值

  2. 方法可以抛出异常,被外面的操作捕获,获取异常类的信息

  3. 支持泛型的返回值

* 实现callable接口   JDK5.0
* 1.创建类实现call方法
* 2.创建接口实现类对象
* 3.将实现类对象的参数传递到FutureTask构造器中,创建FutureTask的对象
* 4.FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
* 5.获取callable中call()的返回值
//    打印出1-100的偶数
class newThread implements Callable {      		//1.创建一个实现Callable接口的类
      public Object  call()  throws Exception{    //回调方法
            int sum=0;                              //装箱
            for(int i=0;i<=100;i++){
                if(i%2==0){
                System.out.println(i);
                sum+=i;
                }
            }
            return sum;
        }
}
public class ThreadNew {
    public static void main(String[] args) {
        newThread newThread = new newThread();     //2.创建callable接口实现类对象
        FutureTask futureTask = new FutureTask(newThread);
         // 泛型 3.将callable接口实现类对象传递到FutureTask构造器中,创建FutureTask对象
        new Thread(futureTask).start();                // FutureTask继承了runnable接口
        //4.将FutureTask的对象作为 参数传递到Thread类的构造器中,并调用start()方法
        try{
            //5.get()返回值即为FutureTask构造器参数 callable实现类重写的call方法的返回值
            Object sum = futureTask.get();             //接收sum值 注意大小写
            System.out.println("总和为"+sum);
        }catch(InterruptedException e){
            e.printStackTrace();
        }catch(ExecutionException e){
            e.printStackTrace();
        }
    }
}

四、线程池

提前创建多个线程,放入线程池中,使用时直接获取,用完放回池中

好处:提高响应速度

降低资源消耗

便于线程管理

corePoolSize:核心池大小

maxmumPoolSize:最大线程数

KeepAliveTime:线程没有任务时最多保持多长时间会终止

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【完整课程列表】 https://download.csdn.net/download/qq_27595745/55555830 完整版精品java课件 Java基础入门教程 Java程序设计 第1章 Java语言概述(共38页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第2章 java语言基础(共31页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第3章 控制结构(共23页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第4章 类和对象(共57页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第5章 继承和接口(共47页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第6章 数组和集合(共44页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第7章 字符串处理(共38页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第8章 异常处理(共27页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第9章 输入输出流(共49页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第10章 JDBC数据库编程(共21页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第11章 图形用户界面1(共27页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第11章 图形用户界面2(共31页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第12章 applet(共16页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第13章 多线程(共24页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第14章 socket网络编程(共24页).ppt

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值