美文网首页
JUC系列----线程API介绍(新建线程,终止线程)

JUC系列----线程API介绍(新建线程,终止线程)

作者: 小陈中间件 | 来源:发表于2020-04-15 23:10 被阅读0次

    1.新建线程

    • 新建线程很简单,只需要 new 一个关键字创建一个线程对象,并start起来即可。
    public class Test1 {
       public static void main(String[] args) {
           Thread thread = new Thread();
           thread.start();
       }
    }
    
    • 线程Thread,有一个run()方法,start()方法就会新建一个线程并执行run()方法。
    • 下面代码也会执行,但不会创建线程,将run()当成一个普通方法去执行。
    • 这里希望大家特别注意,调用start()方法和run()方法的区别。
    public class Test1 {
       public static void main(String[] args) {
           Thread thread = new Thread();
           thread.run();
       }
    }
    
    • 默认情况run方法内部没有任何处理需要我们将任务填进去。
       public static void main(String[] args) {
           Thread thread = new Thread(){
               @Override
               public void run()
               {
                   System.out.println("hello Jage");
               }
           };
           thread.start();
       }
    
    • 上述代码使用的匿名内部类,重载了run方法(),并要求输出 ”hello Jage”。
    • 也可以使用使用继承的方式重载run()方法。
    public class InheritThreadTest extends Thread {
        @Override
        public void run()
        {
            System.out.println("hello Jage");
        }
    }
    
    • 但是java中只准单继承,所以继承是个很宝贵的资源,我们可以使用Runnable接口实现重载run()方法。
    public class RunnableTest implements Runnable {
        @Override
        public void run() {
            System.out.println("hello Jage");
        }
    }
    
    • Thread类有一个重要的构造方法(),用来创建一个实现了Runnable的类的线程并使用run()方法,这也是最常用的做法。
        public Thread(Runnable target) {
            init(null, target, "Thread-" + nextThreadNum(), 0);
        }
    
    public class CreateThread implements Runnable {
        @Override
        public void run() {
            System.out.println("hello Jage");
        }
        public static void main(String[] args) {
            Thread thread = new Thread(new CreateThread());
            thread.start();
        }
    }
    

    2.终止线程

    • 一般来说无需手动关闭,start()执行完run()内部任务后会自行退出,但是凡事有例外例如我们有个任务在循环执行,这个时候我们就需要手动停止线程了。Thread提供stop()方法,只要使用这个方法线程就会立马停止执行终止,但是这个方法被弃用了,原因是太过于暴力,可能将一个执行一般的线程给终止掉了,引起数据不一致的问题。

    • 下面我们用个例子来探讨下stop()方法对数据产生的影响。
      假设我们有一张课程表,里面记录了课程ID和课程名,假设我们现在有两条数据:

    数据1:courseId=1,courseName="1"
    数据2:courseId=2,courseName="2"

    • 我们用一个对象处理数据1和数据2,一般情况是要出保存数据1,要么保存数据2,但是如果我修改的时候,这个对象一半数据是数据1的,另一半是数据2的呢?如果使用单线程,这种情况是不会出现的,但是在多线程的情况下,考虑不周全,就很有可能出现类型的情况。不经思考的使用stop()方法就可能会出现这种问题。

    • Thread.stop()方法在结束线程时,会直接终止线程,并释放该线程所持有的锁,而锁恰恰是用来维持数据一致性的,如果对象在写数据写到一半被强制stop了那这个对象就是坏数据,并且由于锁被释放了,等待锁的另一个线程就会立即读到这个不一致的对象,这个时候再写入数据2的时候就悲剧了。
      这个场景用下面的代码来模拟进行。

    public class StopThreadTest {
       public static Course course = new Course();
    
        @Data
        public static class Course{
            private Integer id;
            private String name;
    
            public Course()
            {
                id=0;
                name="0";
            }
    
            @Override
            public String toString()
            {
                return "Course [id =" + id +", name =" + name +"]";
            }
        }
    
        public static class ChangeDataThread implements Runnable{
    
            @Override
            public void run() {
                while (true)
                {
                    synchronized (course)
                    {
                        int v = (int) (System.currentTimeMillis()/1000);
                        course.setId(v);
                        try
                        {
                            Thread.sleep(100);
                        }catch (InterruptedException e)
                        {
                            e.printStackTrace();
                        }
                        course.setName(String.valueOf(v));
                    }
                    Thread.yield();
                }
            }
        }
    
        public static class ReadDataThread implements Runnable{
    
            @Override
            public void run() {
                while (true)
                {
                    synchronized (course)
                    {
                        if (course.getId() != Integer.parseInt(course.getName()))
                        {
                            System.out.println(course.toString());
                        }
                    }
                    Thread.yield();
                }
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            Thread readThread = new Thread(new ReadDataThread());
            readThread.start();
            while (true)
            {
                Thread changeThread = new Thread(new ChangeDataThread());
                changeThread.start();
                Thread.sleep(150);
                changeThread.stop();
            }
        }
    }
    
    • 执行上述代码很容易就产生了数据不一致的输出,

    Course [id =1586965999, name =1586965998]
    Course [id =1586966000, name =1586965999]


    • Thread除了提供了stop()方法外还提供一种“线程中断”的机制,线程中断严格来说不会立即让线程进行终止不然又会出现上述我们所属的数据不一致问题,线程中断会给线程一个通知,告知需要退出终止线程了,至于何时终止线程,需要线程自行判断。

    • 线程中断有三个方法

    public void interrupt() //线程中断
    public boolean isInterrupted() //判断线程是否线程中断(true | false)
    public static boolean interrupted() //判断线程是否线程中断(true | false),true的话就清除线程中断标志
    
    • 上代码,看我们对线程设置中断后会不会终止。
    public class Test1 {
        public static void main(String[] args) throws InterruptedException{
            Thread thread = new Thread(){
                @Override
                public void run()
                {
                    while (true)
                    {
                        System.out.println("hello Jage");
                        Thread.yield();
                    }
                }
            };
            thread.start();
            Thread.sleep(2000);
            thread.interrupt();
        }
    }
    
    • 即使我们给线程设置了线程中断,也不会立即终止线程执行。如果希望线程在设置线程中断后就终止,需要设置相应的中断处理代码。
        public static void main(String[] args) throws InterruptedException{
            Thread thread = new Thread(){
                @Override
                public void run()
                {
                    while (true)
                    {
                        if (Thread.currentThread().isInterrupted())
                        {
                            break;
                        }
                        System.out.println("hello Jage");
                        Thread.yield();
                    }
                }
            };
            thread.start();
            Thread.sleep(2000);
            thread.interrupt();
        }
    
    • 有一种线程中断情况需要注意,就是当线程在sleep()休眠状态时,进行线程中断的话会抛出InterruptedException异常。

    相关文章

      网友评论

          本文标题:JUC系列----线程API介绍(新建线程,终止线程)

          本文链接:https://www.haomeiwen.com/subject/mlzhvhtx.html