Java 线程的四种创建方式——两个线程交替打印1-100

导读:本篇文章讲解 Java 线程的四种创建方式——两个线程交替打印1-100,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目录

Thread方式创建线程

 Runnable方式创建线程

内部类方式创建线程

第一种:在主函数外定义内部类

第二种:在主函数内创建内部类

Callable方式创建线程


问题:实现两个吸纳成交替打印1-100

Thread方式创建线程

Thread方式适合初学者。步骤如下:

  1. 首先定义一个类MyThread01,继承Thread类,然后重写run()方法;
  2. 同理创建MyThread02;
  3. 创建测试类
MyThread01 类
public class MyThread01 extends Thread {
    MyObject obj;

    public MyThread01(MyObject obj) {
        this.obj = obj;
    }

    @Override
    public void run() {
        while (obj.i<=98) {
            synchronized (obj){
                if (obj.flag){
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName()+"\t"+(++obj.i));
                obj.flag=true;
                obj.notify();
            }
        }
    }
}

 MyThread02 类

public class MyThread02 extends Thread {
    MyObject obj;

    public MyThread02(MyObject obj) {
        this.obj = obj;
    }

    @Override
    public void run() {
        while (obj.i<=98) {
            synchronized (obj){
                if (!obj.flag){
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName()+"\t"+(++obj.i));
                obj.flag=false;
                obj.notify();
            }
        }
    }
}

测试类:MyThread传递的参数必须相同才能实现交替打印

public class Test02 {
    public static void main(String[] args) {
        MyObject obj = new MyObject();
        new MyThread01(obj).start();
        new MyThread02(obj).start();
    }
}

 Runnable方式创建线程

有的人可能会觉得Runnable方式有点多余,已经有了Thread方式,为什么还要这种创建方式呢?我们都知道,Java的继承是单继承,如果我们继承了一个类,就不能在继承其他类。有时候我们创建的类必须要继承某个类,又要用线程,这个时候使用Thread方式创建线程已经不能满足需求了。用Runnable方式正好可以解决这个问题。因为在Java中可以实现多个接口。

第一步:定义一个变量类,用作synchronized的变量

public class Alter {
    public int i=1;
    public boolean flag;
}

第二部:创建第一个线程 Thread-0 

public class Alternate implements Runnable {
    private Alter alter;

    public Alternate(Alter alter) {
        this.alter = alter;
    }

    @Override
    public void run() {
        while (true){
            synchronized (alter){
                if (alter.i<100) {
                    if (alter.flag){
                        try {
                            alter.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName()+"\t"+(alter.i++));
                    alter.flag=true;
                    alter.notify();
                }
            }
        }
    }
}

第三步:创建第二个线程 Thread-1

public class Alternate01 implements Runnable {
    private Alter alter;

    public Alternate01(Alter alter) {
        this.alter = alter;
    }

    @Override
    public void run() {
        while (true){
            synchronized (alter){
                if (alter.i<=100) {
                    if (!alter.flag){
                        try {
                            alter.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName()+"\t"+(alter.i++));
                    alter.flag=false;
                    alter.notify();
                }
            }
        }
    }
}

第四步:创建测试类 。很明显,相比于Thread方式,Runnable方式创建线程多了实例化Runnable类对象的步骤

class AlternateTest {
    public static void main(String[] args) {
        Alter alter=new Alter();

        Alternate a = new Alternate(alter);
        Alternate01 a01 = new Alternate01(alter);
        new Thread(a).start();
        new Thread(a01).start();
    }
}

内部类方式创建线程

这种创建方式显得直接了当,适合高手

第一种:在主函数外定义内部类

因为主函数是用static修饰的,所以这样方式创建的内部类也要用static修饰

public class AlternotePrint {
    //定义内部类,用作synchronized的变量
    static class MyObject{
        boolean flag=false;
        int i=1;
    }

    public static void main(String[] args) {
        MyObject obj = new MyObject();
        //使用匿名内部类的方式创建线程
        new Thread(()->{
            while (true) {
                synchronized (obj){
                    if (obj.i<100) {
                        if (obj.flag){
                            try {
                                obj.wait();//该线程进入无限等待
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(Thread.currentThread().getName()+"\t"+obj.i);
                        obj.i++;
                        obj.flag=true;
                        obj.notify();//唤醒另一个线程
                    }
                }
            }
        }).start();
        new Thread(()->{
            while (true) {
                synchronized (obj){
                    if (obj.i<=100) {
                        if (!obj.flag){
                            try {
                                obj.wait();//该线程进入无限等待
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(Thread.currentThread().getName()+"\t"+obj.i);
                        obj.i++;
                        obj.flag=false;
                        obj.notify();//唤醒另一个线程
                    }
                }
            }
        }).start();
    }
}

第二种:在主函数内创建内部类

这种方式创建的内部类不许要用static修饰

public class Test03 {
    public static void main(String[] args) {
        //定义内部类
        class MyObject{
            boolean flag=false;
            int i=0;
        }

        MyObject obj = new MyObject();
        new Thread(()->{
            while (obj.i<=98) {
                synchronized (obj){
                    if (obj.flag){
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName()+"\t"+(++obj.i));
                    obj.flag=true;
                    obj.notify();
                }
            }
        }).start();

        new Thread(()->{
            while (obj.i<=98) {
                synchronized (obj){
                    if (!obj.flag){
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName()+"\t"+(++obj.i));
                    obj.flag=false;
                    obj.notify();
                }
            }
        }).start();
    }
}

Callable方式创建线程

不管是使用Thread、Runnable,还是内部类的方式创建线程,run()方法的返回值类型都是void,也就是没有返回值,那有时候我们需要返回值怎么办。其实Java中又一种创建线程的方式是又返回值的,那就是Callable 方式。

比如使用线程求1-100的偶数之和

使用之前的三种方式也能达到我们的这样的效果,但是这样是没有返回值的,我们只能在线程中求和并输出总和。

现在用Callable做一下:

第一步:创建MyCallable类实现Callable接口

import java.util.concurrent.Callable;

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() {
        int sum=0;
        for (int i = 1; i <= 100; i++) {
            if (i%2==0){
                sum+=i;
            }
        }
        return sum;
    }
}

第二步:测试类

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class MyCallableTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> task = new FutureTask<>(new MyCallable());
        new Thread(task).start();
        Integer sum = task.get();//返回值
        System.out.println(sum);
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/14622.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!