Java多线程以及线程状态转换

Java多线程以及线程状态转换
Java实现多线程的方式:
1 继承Thread类,重写run方法。
class MyThread extends  Thread{
    public void run(){
        System.out.println(Thread.currentThread().getName()+"MyThread.run()!!");
    }
}
public class testThread {
    public static void main(String [] args){
        MyThread myThread = new MyThread();
        myThread.start();
    }
}
2 实现Runnable接口,重写该接口的run方法。
接口的实现类的实例作为Thread的target作为参数传入带参的Thread构造函数,通过调用start()方法启动线程。
class RunnableDemo implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"Runnable.run()!!");

    }
}

public class testThread {
    public static void main(String [] args){
        Thread thread = new Thread(new RunnableDemo());
        thread.start();
    }
}
3 实现callable接口,重写call()方法
创建Callable接口的实现类,并实现Call方法

创建Callable实现类的实现,使用Future Task类包装Callable对象,该FutureTask对象封装了Callable对象的Call方法的返回值

使用FutureTask对象作为Thread对象的target创建并启动线程

调用FutureTask对象的get()来获取子线程执行结束的返回值
class CallableAndFutrue implements Callable<Object> {

    @Override
    public Object call() throws Exception {
        System.out.println(Thread .currentThread().getName()+"Callable.call!!");
        return null;
    }
}

public class testThread {
    public static void main(String [] args){
        Callable<Object> oneCallable = new CallableAndFutrue();
        FutureTask<Object> oneTask = new FutureTask<>(oneCallable);
        Thread thread1 = new Thread(oneTask);
        thread1.start();
    }
}

可以在任务结束后提供一个返回值,runnable不可以,call方法可以抛出异常,runnable的run方法不行,可以通过运行callable得到的future对象监听目标线程调用call方法的结果,得到返回值。

应用场景:

当父线程想要获得子线程的运行结果时。

Java中六种线程状态:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7HQc3stI-1572353904915)(C:\Users\Z00513~1\AppData\Local\Temp\1572233837426.png)]

1 新建(NEW)

线程创建后没有启动

2 可运行(RUNNABLE)

一旦调用了start方法,线程就处于可运行状态,可运行状态的线程可能正在运行,也可能还没有运行而是正在等待CPU时间片。

3 阻塞(BLOCKED)

处于阻塞状态的线程不会占用CPU资源,线程进入阻塞状态的情况:

(1) 等待获取锁

(2)IO阻塞

"阻塞状态"与”等待状态“的区别:”阻塞状态“在等待着获取一个排他锁,这个时间发生在另外一个线程放弃这个锁的时候;而”等待状态“则是等待一段时间,或者唤醒动作发生。在程序等待进入同步区域的时候,线程将进入这种状态。

4 无限期等待(WAITING)

处于这种状态的线程不会被分配CPU执行时间,要等待被其他线程显式唤醒。以下方法会让线程陷入无限期等等待状态:

(1)没有设置timeout参数的wait方法;

(2)没有设置timeout参数的join方法;

(3)LockSupport.park()方法;

5 限时等待(TIMED_WAITING)

处于这种状态的线程不会被分配CPU执行时间,不过无须等待被其他线程显式唤醒,在一定时间之后它们会由系统自动唤醒。以下方法会让线程进入限时等待状态:

(1)thread的sleep方法;

(2)设置了timeout参数的wait方法;

(3)设置了timeout参数的join方法;

(4)LockSupport.parkNanos();

(5)LockSupport.parkUntil();

6 死亡(TERMINATED)

已经终止线程的线程状态。

几种状态的转换:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0NcEUEkY-1572353904916)(C:\Users\Z00513~1\AppData\Local\Temp\1572233912395.png)]

https://www.cnblogs.com/paddix/p/5381958.html

wait、 notify、 notifyall方法的使用 (object类中)

1 wait 方法

将当前运行的线程挂起(让其进入阻塞状态),直到notify或notifyall方法唤醒线程。

wait方法是一个本地方法,其底层是通过一个叫做监视器锁(monitor),在调用wait方法时必须获得monitor对象的所有权,所以只能在同步的块或者方法中调用,否则会抛出java.lang.IllegalMonitorStateException异常,Java中只能通过Synchronized关键字来实现。

 public synchronized void WaitTest(){
        System.out.println("start---------------");
        try{
            wait(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("end------------------");
    }

    public static void main(String [] args){
        final testWait testWait = new testWait();
        new Thread(new Runnable() {
            @Override
            public void run() {
                testWait.WaitTest();
            }
        }).start();
    }

2 notify 和notifyall

用来唤醒对应对象monitor上等待的线程。两者的区别在于前者只能唤醒一个线程,对其他的线程没有影响,而notifyall则是唤醒所有的线程。

  public synchronized void testWait(){
            System.out.println(Thread.currentThread().getName() +" Start-----");
            try {
                wait(0);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() +" End-------");
        }

        public static void main(String[] args) throws InterruptedException {
            final testNotify test = new testNotify();
            for(int i=0;i<5;i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        test.testWait();
                    }
                }).start();
            }

            synchronized (test) {
                test.notify();
            }
            Thread.sleep(3000);
            System.out.println("-----------分割线-------------");

            synchronized (test) {
                test.notifyAll();
            }
        }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zw4jZ28h-1572353904917)(C:\Users\Z00513~1\AppData\Local\Temp\1572336874795.png)]

sleep 、join方法的使用(Thread类中)

1 sleep

作用是让当前的线程暂停指定的时间,和wait的区别在于:wait方法依赖于同步,而sleep方法可以直接调用,sleep知识暂时让出CPU的执行权,并不释放锁,而wait需要释放锁。

 public synchronized void sleepMethod(){
        System.out.println("Sleep start-----");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Sleep end-----");
    }

    public synchronized void waitMethod(){
        System.out.println("Wait start-----");
        synchronized (this){
            try {
                wait(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Wait end-----");
    }

    public static void main(String[] args) {
        final testSleep test1 = new testSleep();

        for(int i = 0;i<3;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    test1.sleepMethod();
                }
            }).start();
        }


        try {
            Thread.sleep(10000);//暂停十秒,等上面程序执行完成
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("-----分割线-----");

        final testSleep test2 = new testSleep();

        for(int i = 0;i<3;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    test2.waitMethod();
                }
            }).start();
        }

    }

可以看出sleep方法实现的暂停,程序是顺序进入同步块的,只有当上一个线程执行完成的时候,下一个线程才能进入同步方法,sleep暂停期间一直持有monitor对象锁,其他线程是不能进入的。而wait方法则不同,当调用wait方法后,当前线程会释放持有的monitor对象锁,因此,其他线程还可以进入到同步方法,线程被唤醒后,需要竞争锁,获取到锁之后再继续执行。

2 join

join方法的作用是父线程等待子线程执行完成后再执行,也就是相当于将异步执行的线程合并为同步的线程。join有三种实现的方式。

 public void run() {

        try {
            System.out.println(Thread.currentThread().getName() + " start-----");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + " end------");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //不使用join
    public static void main(String[] args) {
        for (int i=0;i<5;i++) {
            Thread test = new Thread(new testJoin());
            test.start();
        }

        System.out.println("Finished~~~");
    }

    //使用join
    // public static void main(String[] args) {
    //     for (int i=0;i<5;i++) {
    //         Thread test = new Thread(new testJoin());
    //         test.start();
    //         try {
    //             test.join(); //调用join方法
    //         } catch (InterruptedException e) {
    //             e.printStackTrace();
    //         }
    //     }
    //
    //     System.out.println("Finished~~~");
    // }
synchronized原理

https://blog.csdn.net/javazejian/article/details/72828483

在 Java 中,关键字 synchronized可以保证在同一个时刻,只有一个线程可以执行某个方法或者某个代码块(主要是对方法或者代码块中存在共享数据的操作),同时我们还应该注意到synchronized另外一个重要的作用,synchronized可保证一个线程的变化(主要是共享数据的变化)被其他线程所看到(保证可见性,完全可以替代Volatile功能),这点确实也是很重要的。

https://www.cnblogs.com/paddix/p/5381958.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值