1.用两种方式实现两个线程,一个线程负责打印1-2600,另一个线程打印A-Z,反复打印10

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1.用两种方式实现两个线程,一个线程负责打印1-2600,另一个线程打印A-Z,反复打印10相关的知识,希望对你有一定的参考价值。

1.用两种方式实现两个线程,一个线程负责打印1-2600,另一个线程打印A-Z,反复打印100遍
2.实现两个线程,一个线程打印1-52,另一个线程打印A-Z,要求输出的结果: 1 2 A 3 4 B 5 6 C 7 8 D 9 10 11 12 ... 52 E F G H I J K ... X Y Z
3.利用线程的通信机制,用两个线程打印以下的结果: 1 2 A 3 4 B 5 6 C 7 8 D ... 49 50 Y 51 52 Z

1:第一种方式,继承Thread:
public class ThreadDemo
/*用两种方式实现两个线程,一个线程负责打印1-2600,另一个线程打印A-Z,反复打印100遍*/
public static void main(String[] args)
Task1 task1 = new Task1();
Task2 task2 = new Task2();
task1.start();
task2.start();


class Task1 extends Thread
public void run()
for(int a=0;a<100;a++)
for(int i=1;i<=2600;i++)
System.out.println(i);




class Task2 extends Thread
public void run()
for(int a=0;a<100;a++)
for(char i='A';i<='Z';i++)
System.out.println(i);




第二种方式,实现Runnable接口:
public class ThreadDemo2
public static void main(String[] args)
Thread t1 = new Thread(new Task3());
Thread t2 = new Thread(new Task4());
t1.start();
t2.start();


class Task3 implements Runnable
public void run()
for(int a=0;a<100;a++)
for(int i=1;i<=2600;i++)
System.out.println(i);






class Task4 implements Runnable
public void run()
for(int a=0;a<100;a++)
for(char i='A';i<='Z';i++)
System.out.println(i);





2:用多线程加锁:
参考技术A 先找到数字和字母的规律再说,这个规律我可没看出来 参考技术B 你先要告诉大家,你想用什么语言实现啊!

Java多线程带你用不一样的思维看创建线程的两种方式

文章目录

创建线程的两种方式

通过实现 Runnable 接口

public class CreateThread 
//  继承 Thread 类来
    static class MyThread extends Thread
        @Override
        public void run() 
            System.out.println("Hello MyThread");
        
    

//  实现 Runnable 接口:这个方式更灵活,因为实现接口后,可以继承其他类
    static class MyRun implements Runnable
        @Override
        public void run() 
            System.out.println("Hello MyRun");
        
    



    public static void main(String[] args) 
        new MyThread().start();
        new Thread(new MyRun()).start();
        new Thread(()->
            System.out.println("hello lambda!");
        ).start();
    


上面是主流的创建线程的两种方法,那么我们看一下这两种方法有什么区别吧
Runnable:可以看到使用 Runnable 来创建线程,使用 Runnable 接口引向一个匿名内部类,该内部类重写了 Runnable 接口的run方法,再次之后,仍需要创建一个新的线程,然后传入 runnable ;
Thread : 直接继承 Thread 然后重写 run 方法

从面对对象的角度来思考:
两种方法都是为了构造一个 Thread 类,大家可以看到实现了 runnable 接口后,仍然是创建了一个新的线程,把接口作为 Thread 的构造方法参数传入

public Thread(Runnable target) 
    init(null, target, "Thread-" + nextThreadNum(), 0);

start 和 run 方法解析

在初次使用的时候,大家很容易看见,我们重写的是 run 方法,那么为什么调用的时候,调用的却是 start 方法

start启动新线程:通知JVM,有空闲就创建新线程,何时创建由线程调度器控制(并非调用start方法就会创建,即两个调用start的方法顺序不代表线程的创建顺序)

调用完start后,在主线程中启动

    public synchronized void start() 
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try 
            start0();
            started = true;
         finally 
            try 
                if (!started) 
                    group.threadStartFailed(this);
                
             catch (Throwable ignore) 
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            
        
    

为什么不能调用 run 方法 调用了会发生什么事情

public static void main(String[] args) 
    Runnable runnable = ()->
        System.out.println(Thread.currentThread().getName());
    ;
    runnable.run();

    new Thread(runnable).start();

main:因为在调用的时候,我们使用的是接口.方法,实际上 runnable 接口指向一个匿名内部类,这个类重写了 run 方法,我们在调用的时候,调用的是普通方法 run ,并且是在主函数里面调用的 主线程就是 main
Thread-0 :

重复调用 start 方法会发生什么事情

Exception in thread “main” java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:708)
at StartTwice.main(StartTwice.java:5)

为什么不能重复调用
原因:一旦开始线程完毕,会进入终止状态,无法回退

if (threadStatus != 0)
 throw new IllegalThreadStateException();

threadStatus:
Java 线程状态,已初始化以指示线程“尚未启动”

彩蛋:同时用两种方法来实现同一个线程,会遇到什么

大家可能没有考虑过,如果new Thread 类,并且传入一个 runnable 重写 runnable 接口的 run 方法的同时,重写Thread 类的 run 方法会发生什么事情

public static void main(String[] args) 
        new Thread(new Runnable() 
            //匿名内部类
            @Override
            public void run() 
                System.out.println("Runnable");
            
        )
            //重写
            @Override
            public void run() 
                System.out.println("Thread");
            
        .start();
    

从面向对象的思想去考虑:
刚才使用的匿名内部类,然后重写了Thread,
两种,一种是重写run方法,一种是给run传入target

我们看看源码,才能知道为什么调用的是 Thread 类的 run

如果该线程是使用单独的 unnable 运行对象构造的,则调用该 Runnable 对象的run 方法;否则,此方法不执行任何操作并返回。  Thread 的子类应覆盖此方法。
 private Runnable target;
@Override
public void run() 
    if (target != null) 
        target.run();
    

解释一下 targer 是我们使用 runnable 方法来构建Thread 类时传入的参数。
这个三行代码是什么,大家思考一下,这个是 Thread 类的 run 方法,我们平时使用的新建 Thread 创建线程,就会重写这个方法,即这个三行代码是被重写的,不会调用。但是如果仅仅只是 runnable 新建线程,我们只是重写了 Runnable 接口的 run 方法,启动线程 Thread 调用的就是未被重写的 这三行Thread 类的run方法中的语句。但两者都有时,Thread 的 run 方法就会被前者覆盖,上方的 run 方法中三行代码永远不会执行

小知识:调用start方法,线程就会立刻启动吗?

  1. 调用了 start 方法,线程就立刻启动了吗???

在调用 start 方法后,其实先通知JVM,让其有空闲就创建新线程,但是何时真正创建由线程调度器决定。即,在某些情况下,可能会出现先 start 的线程后执行

以上是关于1.用两种方式实现两个线程,一个线程负责打印1-2600,另一个线程打印A-Z,反复打印10的主要内容,如果未能解决你的问题,请参考以下文章

面试常考:C#用两个线程交替打印1-100的五种方法

Java多线程带你用不一样的思维看创建线程的两种方式

Java多线程带你用不一样的思维看创建线程的两种方式

线程创建_同步_通信

java线程之间通信,多种方式实现生产者消费者模式

经典面试题——两个线程交替打印奇数和偶数