Java线程与多线程

 

计算机可以将多种活动同时进行,这种思想放在Java中被称为并发,而将并发完成的每一件事情称为线程。

1.线程和多线程

在Java中,并发机制非常重要。在以往的程序设计中,我们都是一个任务完成后再进行下一个任务,这样下一个任务的开始必须等待前一个任务的结束。Java语言提供了并发机制,程序员可以在程序中执行多个线程,每一个线程完成一个功能,并与其他线程并发执行,这种机制被称为多线程。
一个线程则是进程中的执行流程,一个进程中可以同时包括多个线程,每个线程也可以得到一小段程序的执行时间,这样一个进程就可以具有多个并发执行的线程。在单线程中,程序代码按调用顺序依次往下执行。如果需要一个进程同时完成多段代码的操作,就需要使用多线程。

2.创建线程

通过java.lang.Thread类的对象来代表线程

创建方式一:继承Thread类
  1. 创建MyThread类,让其继承Thread类并重写run()方法。
public class MyThread0 extends Thread{
    //必须重写run方法
    //run方法描述线程的执行内容
    @Override
    public void run() {
        for (int i = 0; i < 4; i++) {
            System.out.println("子线程正在输出:" + i);
        }
    }
}
  1. 创建MyThread类的实例对象,即创建一个新线程。
  2. 调用start()方法,启动线程。
public class test {
    //主线程和子线程执行是随机的
    public static void main(String[] args) {
        Thread t=new MyThread0();
        //注意是调用start不是调用run
        t.start();
        for (int i = 0; i < 4; i++) {
            System.out.println("主线程正在输出:" + i);
        }
    }
}

优点:编码简单
缺点:线程类已经继承了Thread,无法继承其他类,不利于功能的扩展

创建方式2:实现Runnable接口
  1. 创建MyRunnable类实现Runnable接口。Runnable接口只有一个run方法,源代码如下:
public interface Runnable {
    public abstract void run();
}
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 4; i++) {
            System.out.println("子线程1输出:" + i);
        }
    }
}
  1. 创建MyRunnable类的实例对象myRunnable
  2. 把实例对象myRunnable作为参数来创建Thread类的实例对象thread,实例对象thread就是一个新线程。
    调用start()方法,启动线程。
    一并演示三种简化方式:
public class test1 {
    public static void main(String[] args) {
        Runnable runnable = new MyRunnable();//多态
        new Thread(runnable).start();

        //简化形式1:匿名内部类
        Runnable runnable1=new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 4; i++) {
                    System.out.println("子线程2输出:" + i);
                }
            }
        };
        new Thread(runnable1).start();

        //简化形式2:匿名内部类(不创建变量)
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 4; i++) {
                    System.out.println("子线程3输出:" + i);
                }
            }
        }).start();

        //简化形式3:匿名内部类(lambda表达式)
        new Thread(()-> {
                for (int i = 0; i < 4; i++) {
                    System.out.println("子线程3输出:" + i);
                }
            }
        ).start();

        for (int i = 0; i < 4; i++) {
            System.out.println("主线程输出:" + i);
        }
    }
}

优点:任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强。
缺点:需要多一个Runnable对象。

创建方式3:实现 Callable 接口

Callable接口只有一个call()方法,源码如下:

public interface Callable<V> {
    V call() throws Exception;
}

从源码我们可以看到Callable接口和Runnable接口类似,它们之间的区别在于run()方法没有返回值,而call()方法是有返回值的。

  1. 创建MyCallable类实现Callable接口。
import java.util.concurrent.Callable;
//要使用泛型来指定返回的结果类型
public class MyCallable implements Callable<String> {
    private int n;

    public MyCallable(int n) {
        this.n = n;
    }

    @Override
    public String call() throws Exception {
        int sum=0;
        for (int i = 0; i < n; i++) {
            sum+=i;
        }
        return "结果是:"+sum;
    }
}
  1. 创建MyCallable类的实例对象myCallable
  2. 把实例对象myCallable作为参数来创建FutureTask类的实例对象futureTask
  3. 把实例对象futureTask作为参数来创建Thread类的实例对象thread,实例对象thread就是一个新线程。
    调用start()方法,启动线程。
public class test2 {
    public static void main(String[] args) throws Exception {
        // 创建一个Callable的对象
        Callable<String> cl=new MyCallable(100);
        // 把Callable的对象封装成一个FutureTask对象(任务对象)
        // 未来任务对象的作用?
        // 是一个任务对象,实现了Runnable对象.
        // 可以在线程执行完毕之后,用未来任务对象调用get方法获取线程执行完毕后的结果。
        FutureTask<String> ft=new FutureTask<>(cl);
        // 把任务对象交给一个Thread对象
        Thread t=new Thread(ft);
        t.start();
        // 获取线程执行完毕后返回的结果。
        // 注意:如果执行到这儿,假如上面的线程还没有执行完毕
        // 这里的代码会暂停,等待上面线程执行完毕后才会获取结果。
        System.out.println(ft.get());
    }
}

优点:任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强。可以在线程执行完毕后获取线程执行的结果。
缺点:编码复杂

3.Tread的常用方法

public class test3 {
    public static void main(String[] args) {
        Thread t1 = new MyThread("1号线程");
        // t1.setName("1号线程");
        t1.start();
        System.out.println(t1.getName()); // Thread-0(默认)

        Thread t2 = new MyThread("2号线程");
        // t2.setName("2号线程");
        t2.start();
        System.out.println(t2.getName()); // Thread-1

        // 主线程对象的名字
        // 哪个线程执行它,它就会得到哪个线程对象。
        Thread m = Thread.currentThread();//得到的是主线程的名字
        m.setName("最牛的线程");
        System.out.println(m.getName()); // main

        for (int i = 1; i <= 5; i++) {
            System.out.println(m.getName() + "线程输出:" + i);
        }
    }
}

输出结果如下:

全文完

原创文章,作者:速盾高防cdn,如若转载,请注明出处:https://www.sudun.com/ask/87662.html

(0)
速盾高防cdn的头像速盾高防cdn
上一篇 2024年6月2日
下一篇 2024年6月2日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注