Java教程

java多线程基础总结

本文主要是介绍java多线程基础总结,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Java多线程编程

1,一个线程的生命周期

在这里插入图片描述

  • 新建状态
  • 就绪状态:当线程对象调用了start()方法之后,该线程即进入就绪转态;就绪状态的线程处于就绪队列中,要等待JVM线程调度器的调度
  • 运行状态:如果就绪状态的线程获取CPU资源,就可以执行run()方法。
  • 阻塞状态:若执行了sleep()(睡眠),suspend()(挂起)方法,或者失去了所占用的资源后,线程进入阻塞状态;再次之后,可重新进入就绪状态;
    • 等待阻塞:运行中执行wait()方法。
    • 同步阻塞:线程获取synchronized同步锁失败(同步锁被其他线程占用)。
    • 其他阻塞:如,通过调用sleep()join()发出IO请求时,会进入阻塞状态。当sleep() 状态超时join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
  • 死亡状态:线程完成或者终止条件触发;

2,线程优先级

每一个 Java 线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。

Java 线程的优先级是一个整数,其取值范围是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY ),1-10级。

默认情况下,每一个线程都会分配一个优先级NORM_PRIORITY(5)

3,线程创建的方法

  • 继承Thread类;
  • 实现Runnable接口;
  • Callable和Future创建;

3.0 关于Thread类

3.0.1 Thread类方法

  • 1,获取线程的名称:
    • 使用Thread类中的方法String getName()返回线程的名称
    • 可以获取到当前正在执行的线程static Thread currentThread(),使用线程中的getName()方法获取线程
  • 2,设置线程名称:
    • 使用void setName(String name)方法改变线程名称
    • 创建一个带参构造方法,参数为线程的名称,调用父类的带参构造方法Thread(String name),让父类给取一个名字
  • 3,线程休眠
    • public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),毫秒数结束之后,线程继续执行
public class MyThread extends Thread{
    @Override
    public void run(){
    	System.out.println(getName());
    }
}
public class Demo01GetThread{
    //创建Thread类的子类对象
    MyThread mt=new MyThread();
    //调用start()方法,开启新线程
    mt.start();//--------------------------"Thread-0"
    new MyThread().start();//--------------"Thread-1"
    new MyThread().start();//--------------"Thread-2"
}

public class MyThread extends Thread{
    @Override
    public void run(){
        Thread t=Thread.currentThread();
    	System.out.println(t);
        System.out.println(t.getName());
    }
}
public class Demo01GetThread{
    //创建Thread类的子类对象
    MyThread mt=new MyThread();
    //调用start()方法,开启新线程
    mt.start();//--------------------------"Thread[Thread-0,5,main]/Thread-0"
    new MyThread().start();//--------------"Thread[Thread-1,5,main]/THread-1"
    new MyThread().start();//--------------"Thread[Thread-2,5,main]/Thread-2"
    System.out.println(Thread.currentThread().getName());//-------"main"
}
public class Demo01GetThread{
    //创建Thread类的子类对象
    MyThread mt=new MyThread();
    mt.setName("张三");
     System.out.println(mt.getName());
}

public class MyThread extends Thread{
    @Override
    public MyThread(){}
    public MyThread(String name){
        super(name);//调用父类的带参构造方法``Thread(String name),让父类给取一个名字
    }
    public void run(){
        Thread t=Thread.currentThread();
    	System.out.println(t);
        System.out.println(t.getName());
    }
}
public class Demo01Sleep{
    public static void main(String[] args){
        for(int i=1;i<=60;i++){
            System.out.println(i);
            try{
                Thread.sleep(1000);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

3.1 继承Thread类

将类声明为Tread的子类,该子类重写Thread类的run方法。接下来可以分配该子类的实例。

步骤:

  • 1,创建一个Thread类的子类;
  • 2,在Thread类的子类中重写Thread类中的run()方法,设置线程任务(即线程要做什么);
  • 3,创建T该子类对象;
  • 4,调用Thread类中的Start()方法,开启新线程,间接执行run方法;
    • void start()使该线程开始执行; Java虚拟机调用该线程的run方法。
    • 结果是两个线程并发地运行:当前线程(main线程)和另一个线程(创建的新线程,执行其run 方法)。
    • 多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。

java程序属于抢占式调度, 那个线程的优先级高,那个线程优先执行;同一个优先级,随机选择一 个执行

public class MyThread extends Thread{
    @Override
    public void run(){
        for(int i=0;i<20;i++){
            System.out.println("run:"+i);
        }
    }
}

public class Demo01Tread{
    public static void main(String[] args){
        //创建子类对象
        MyThread mt=new MyThread();
        //调用start()方法,间接执行run()方法
        mt.start();
        //main主线程,此时两线程并发执行
        for(int i=0;i<20;i++){
            System.out.println("main:"+i)
        }
    }
}

执行结果:

并发的抢占CPU资源

在这里插入图片描述

3.2 实现Runnable接口

创建线程的另-种方法是声明实现Rumable接口的类。该类然后实现run方法。然后可以分配该类的实例,在创建Thread 时作为一个参数来传递并启动。

java. Lang. Runnable
Runnable接口应该由那些打算通过某一线程执行其实例的类来实现。 类必须定义一个称为run 的无参数方法。

java. Lang. Thread类的构造方法
Thread(Runnable target) 分配新的Thread 对象。
Thread(Runnable target, String name)分配新的Thread 对象。

步骤:

  • 1,创建实现Runnable接口的实现类
  • 2,重写接口中的run()方法
  • 3,创建该Runnable接口实现类的对象
  • 4,用该对象创建Thread类对象
  • 5,调用Thread类对象中的start()方法,开启新线程
public class MyRunClass implements Runnable{//--------实现Runnable接口
    @Override
    void run(){	//------------------------------------重写run方法
        System.out.println("Runnable线程:"+Thread.currentThread().getName());
    }
}

public class Demo01Runnable{
    public static void main(String[] args){
        //写法1
        MyRunClass rc=new MyRunClass();//--------创建该Runnable接口实现类的对象
        Thread mt=new Thread(rc);//----------用该对象创建Thread类对象
        mt.start();//----------------------------调用Thread类对象中的start()方法,开启新线程
        
        //写法2
        new Thread(){
            @Override
            public void run(){
                for(int i=0;i<20;i++){
                    System.out.println(i);
                }
            }
        }.start();
        //写法3
        Runnable r=new Runnable(){
            @Override
            public void run(){
                for(int i=0;i<20;i++){
                    System.out.println(i);
                }
            }
        }
        new Thread(r).start();
        //写法4
        new Thread(new Runnable(){
            @Override
            public void run(){
                for(int i=0;i<20;i++){
                    System.out.println(i);
                }
            }
        }).start();
        //写法5:lambda表达式
        new Thread(()->{
            for(int i=0;i<20;i++){
                    System.out.println(i);
                }
        }).start();
    }
}

实现Runnable接口创建新线程的好处:

  • 1,避免了单继承的局限性

    • 一个类只能继承一一个类(- -个人只能有一-个亲爹),类继承了Thread类就不能继承其他的类
      实现了Runnable接口,还可以继承其他的类,实现其他的接口。
  • 2,增强了程序的扩展性,降低了程序的耦合性

    • 实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解耦)。
  • 实现Runnable接口的方式,一个任务可以用多个线程来执行

3.3 实现Callable接口

  • 1,实现Callable的接口,需要返回值类型
  • 2,重写call方法,需要抛出异常值
  • 3,创建目标Callalbe对象,n个;
  • 4,创建执行服务对象ExecutorService serExecutorService ser =Executors.newFixedThreadPool(n);
  • 5,提交执行:Future<T> res=ser.submit(call1);
  • 6,获取结果:res.get()
  • 7,关闭服务:ser.shutdownNow()
//1,实现Callable的接口,需要返回值类型
public class TestCallable implements Callable<Boolean>{
    private String url;
    private String name;
    public TestCallable(String url,String name){
        this.url=url;
        this.name=name;
    }
//2, 重写call方法,需要抛出异常值   
    @Override
    public Boolean call(){
        WebDownloader webDownloader=new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名为:"+name);
        return true;
    }
    public static void main(String[] args){
//3,创建目标Callalbe对象,n个;    
        TestCallable t1=new TestCallable("https://kgoe.ego.cn/gei.img/1");
        TestCallable t2=new TestCallable("https://kgoe.ego.cn/gei.img/2");
        TestCallable t3=new TestCallable("https://kgoe.ego.cn/gei.img/3");
//4,创建执行服务对象ExecutorService        
        ExecutorService ser =Executors.newFixedThreadPool(3);
//5,提交执行
        Future<Boolean> r1=ser.submit(t1);
        Future<Boolean> r2=ser.submit(t2);
        Future<Boolean> r3=ser.submit(t3);
//6,获取返回值
        boolean rs1=r1.get();
        boolean rs2=r2.get();
        boolean rs3=r3.get();
//7,关闭执行服务
        ser.shutdownNow();
    }
}

4,多线程内存图解

在这里插入图片描述
新的线程会开辟新的栈空间

这篇关于java多线程基础总结的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!