JAVA多线程(基础)

1.进程与线程

1.1进程与线程的概念

进程概念:操作系统中一个程序的执行周期(例如:打开qq然后关闭qq这就是一个进程)

                 进程是操作系统中资源分配的最小单位

线程概念:进程中的一个任务

                 线程是操作系统中资源调度的最小单位

进程与线程的区别

  • 地址空间:同一进程中的线程共享本进程的地址空间,而进程之间是独立的地址空间
  • 资源内存:同一进程中的线程共享本进程的资源,内存(堆内存和方法区内存,栈内存不共享),而进程的资源是彼此独立的
  • 两者均可并发执行(多个任务轮流切换执行)

1.2线程状态

创建,就绪,运行,阻塞,终止

2.多线程实现

2.1继承Thread类(实现了Runnable接口)

示例:

class MThread extends Thread{
    private String cat;
    public MThread(String cat){
        this.cat = cat;
    }
    public void run(){
        for(int i = 0; i < 5;i++){
            System.out.println(this.cat+"喜欢"+i);
        }
    }
}
public class MyThread {
    public static void main(String[] args) {
        Thread thread1 = new MThread("小花");
        Thread thread2 = new MThread("小白");
        Thread thread3 = new MThread("桔子");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

为什么调用start()方法而不是run()方法?

  • run()方法是多线程程序的一个约定。所有的多线程代码都在run方法里面。
  • 调用start()方法,会自动调用线程的run()方法
  • start()方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码:
  • 调用Thread类的 start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法。
  • run()方法只是类的一个普通方法,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。

2.1实现Runnable接口

示例1:

class MThread implements Runnable{
    private String cat;
    public MThread(String cat){
        this.cat = cat;
    }
    public void run(){
        for(int i = 0; i < 5;i++){
            System.out.println(this.cat+"喜欢"+i);
        }
    }
}
public class MyThread {
    public static void main(String[] args) {
        Mthread thread1 = new MThread("小花");
        Mthread thread2 = new MThread("小白");
        Mthread thread3 = new MThread("桔子");
        new Thread(thread1).start();
        new Thread(thread2).start();
        new Thread(thread3).start();
    }
}

示例二:利用匿名内部类

public class MyThread {
    public static void main(String[] args) {
        new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println("小花最调皮");
            }
        }).start();
    }
}

示例三:利用Lamdba表达式

public class MyThread {
    public static void main(String[] args) {
        Runnable runnable = ()-> System.out.println("小花最调皮");
        new Thread(runnable).start();
    }
}

Thread与Runnable的区别(Runnable优势)

  • 实现Runnable接口更容易实现资源的共享
  • 避免了单继承的局限性
  • 线程池只能放入实现Runnable,Callable接口的类,而不能直接放入继承Thread的类

2.3实现Callable接口

class Mthread implements Callable{
    private int cat = 4;
    @Override
    public Object call() throws Exception {
        while(cat > 0){
            System.out.println("还有"+cat+"只猫");
            cat--;
        }
        return "猫咪回家了,撸猫明请早";
    }
}
public class MyThread {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> callable = new FutureTask<>(new Mthread());
        new Thread(callable).start();
        System.out.println(callable.get());
    }
}

Runnable中的run()方法没有返回值,但是很多时候需要一些返回值,例如某些线程执行完成后可能带来一些返回结果,这种情况下就只能利用Callable来实现多线程。

3.多线程的常用操作方法

3.1线程的命名和取得

如果没有设置线程名称,则会自动分配一个线程名称

  • public final synchronized void setName(String name);//创建线程的时候设置名称
  • public Thread(Runnable target,String name);//设置线程名称
  • public final String getName();//获得线程名称
public class MyThread{
    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                //设置线程名称
                this.setName("小白");
                System.out.println(this.getName());
            }
        }.start();
        //通过构造方法设置名称
        new Thread("小花"){
            public void run(){
                System.out.println(this.getName());
            }
        }.start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                //获得当前线程名称
                System.out.println(Thread.currentThread().getName());
            }
        }).start();
    }
}

3.2线程休眠(sleep方法)

sleep():让线程暂缓一下,到了预定的时间后再继续执行。在此期间,会交出CPU的使用权,但是不会释放锁。也就是说,若当前线程持有某个对象的锁,那么sleep后,其他的线程无法访问此对象。并且调用此方法后,线程回到阻塞态。

  • public static native void sleep(long millis) throws InterruptedException
class MThread implements Runnable {
    private String cat;
    public void run() {
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "喜欢" + i);
        }
    }
}

3.3 线程让步(yield方法)

yield():暂停当前线程的执行,转而执行其他线程。会交出CPU的使用权,但是不能控制具体的交出时间。并且调用此方法不会释放锁。并且调用此方法后,线程回到就绪态。

class MThread implements Runnable {
    private String cat;
    public void run() {
        for (int i = 0; i < 5; i++) {
                Thread.yield();
            System.out.println(Thread.currentThread().getName() + "喜欢" + i);
        }
    }
}

3.4join()方法

join():等待该线程终止。也就说必须等该线程执行完之后,才能执行要执行的线程。

public class MyThread{
    public static void main(String[] args) {
       Thread thread1 = new Thread(new Runnable() {
           @Override
           public void run() {
               for (int i = 0;i < 5;i++){
                   System.out.println(Thread.currentThread().getName());
               }
           }
       });
        Thread thread2 = new Thread(){
            @Override
            public void run() {
                for (int i = 0;i < 5;i++){
                    try {
                        thread1.join();
                        System.out.println(Thread.currentThread().getName());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread1.start();
        thread2.start();
    }
}

3.5线程停止

  • 设置标记位,可以是线程正常退出。
class MThread implements Runnable {
    private boolean flag = true;
    @Override
    public void run() {
        int i = 1;
        while (flag) {
            try {
                Thread.sleep(1000);
                System.out.println("第"+i+"次执行,线程名称为"+Thread.currentThread().getName());
                i++;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}
public class MyThread{
    public static void main(String[] args) throws InterruptedException {
        MThread myThread = new MThread();
        new Thread(myThread).start();
        Thread.sleep(4500);
        myThread.setFlag(false);
    }
}
  •  使用stop方法强制使线程退出(弃用)

stop方法会解除线程获得的所有锁定,当调用stop方法时,这个线程对象正在运行的线程会立即停止,因此可能会产生不完整的残废数据。

  •  使用Thread类中的一个 interrupt() 可以中断线程。

interrupt() 方法只是改变中断状态而已,它不会中断一个正在运行的线程。

class MThread implements Runnable {
    @Override
    public void run() {
        boolean bool = Thread.currentThread().isInterrupted();
        while (!bool){
            try {
                Thread.sleep(1000);
                System.out.println("阻塞情况下"+bool);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

3.6线程优先级

  •  最高优先级:public final static int MAX_PRIORITY = 10;
  • 中等优先级:public final static int NORM_PRIORITY = 5;
  • 最低优先级:public final static int MIN_PRIORITY = 1;
  • 设置优先级:public final void setPriority(int newPriority)
  • 获得优先级:public final int getPriority()
class MThread implements Runnable {
    @Override
    public void run(){
            System.out.println(Thread.currentThread().getPriority());
    }
}
public class MyThread{
    public static void main(String[] args) throws InterruptedException {
        MThread mt = new MThread();
        Thread t1 = new Thread(mt,"1") ;
        Thread t2 = new Thread(mt,"2") ;
        Thread t3 = new Thread(mt,"3") ;
        t1.setPriority(6);
        t2.setPriority(Thread.MIN_PRIORITY);
        t3.setPriority(Thread.MAX_PRIORITY);
        t1.start();
        t2.start();
        t3.start();
    }

3.7守护线程

java中有两种线程:用户线程和守护线程

典型的守护线程为垃圾回收线程,只要当前JVM进程中存在任何一个非守护进程还没有结束,那么守护进程就要一直工作。只有当最后一个非守护线程执行完后,守护线程才会关闭

可以用isDaemon()方法进行区别

class MThread implements Runnable {
    @Override
    public void run(){
            System.out.println(Thread.currentThread().isDaemon());
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43573534/article/details/90037608