线程详解

来源:互联网 发布:虚拟机ubuntu无法联网 编辑:程序博客网 时间:2024/06/05 09:49

java多线程解决了什么问题?

并发通常可以解决“速度”和“设计可管理性问题”。

“并行”和“并发”的区别在于,“并行”是多个进程同时执行。而“并发”表面上看是多个线程同时执
行,而实际上是多个线程在轮换执行,也就是说某一时刻只有一个线程在运行。但是由于处理器的运行速度非常之快,所以给人的感觉是多个线程在同时运行。

线程/进程 开销 资源 线程 小 共享所在进程中的资源 进程 大 彼此间资源独立

说多线程解决“速度问题”有一个前提。

就是在多cpu的情况下。
当在单cpu时,多线程只能起到同时处理多个任务的作用,而并不会提高运行速度。

我们可以想象一种情境,就是如果我们需要同时给100个人打电话通知他们尽快回校参加培训。

如果在单线程的情况下,就等同于用同一台电话拨打100次通话。那么这时候如果该线路出现问题,后面的人都无法得到通知。
如果是多线程的情况下,如果某一个线路出现了阻塞,并不影响其他线路工作。


实现多线程的方式

  • 通过实现Runnable接口
  • 继承自Thread类
 //通过实现Runnable  public class RocketFacotry1 implements Runnable {       //事实上任何线程的执行流程都是在Runnable接口的run()方法中执行        @Override        public void run() {            System.out.println(Thread.currentThread().getName() + "号生产线完成了一量火箭的组装!");        }         public static void main(String[] args) {            RocketFacotry1 facotry1 = new RocketFacotry1();            new Thread(facotry1).start();            new Thread(facotry1).start();        }}

运行结果
Thread-1号生产线完成了一量火箭的组装!
Thread-0号生产线完成了一量火箭的组装!

    //通过继承Thread    public class RocketFactory2 extends Thread {        @Override        public void run() {            super.run();            System.out.println(Thread.currentThread().getName() + "号生产线完成了一量火箭的组装!");        }         public static void main(String[] args) {            new RocketFactory2().start();            new RocketFactory2().start();         }}
运行结果Thread-1号生产线完成了一量火箭的组装!

Thread-0号生产线完成了一量火箭的组装!
Thread内部也是通过执行Runnable接口的run()来运行线程

      @Override    public void run() {        //此处的target是Runnable        if (target != null) {            target.run();        }    }

Daemon线程

  • Daemon线程即守护线程,后台线程的特点是优先级比较低。当jvm中的非守护线程都运行结束的时候,那么Daemon守护线程也跟着结束。所以在使用守护线程的时候要慎重些

  • jvm的垃圾回收线程就是典型的(Daemon)守护线程。当jvm中没有其他的线程在运行时,垃圾回收线程也就跟着结束了

  • setDaemon一定要在线程的start之前设置,否则抛出IllegalThreadStateException异常

    public static void main(String[] args) {    Thread thread = new Thread(() -> {        int num = 0;        while (true) {            try {                Thread.sleep(20);                System.out.println(Thread.currentThread().getName() + " is running!timestamp is " +     System.currentTimeMillis() + " ,Daemon线程运行了" + num++ + "次");            } catch (InterruptedException e) {                e.printStackTrace();            }        }    });    thread.setDaemon(true);    thread.start();    try {        Thread.sleep(500);        Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("JVM运行结束,timestamp is " + System.currentTimeMillis())));    } catch (InterruptedException e) {        e.printStackTrace();    }}

    Thread-0 is running!timestamp is 1489134646030 ,Daemon线程运行了0次
    Thread-0 is running!timestamp is 1489134646050 ,Daemon线程运行了1次
    Thread-0 is running!timestamp is 1489134646070 ,Daemon线程运行了2次
    Thread-0 is running!timestamp is 1489134646090 ,Daemon线程运行了3次
    Thread-0 is running!timestamp is 1489134646117 ,Daemon线程运行了4次
    Thread-0 is running!timestamp is 1489134646137 ,Daemon线程运行了5次
    Thread-0 is running!timestamp is 1489134646157 ,Daemon线程运行了6次
    Thread-0 is running!timestamp is 1489134646177 ,Daemon线程运行了7次
    Thread-0 is running!timestamp is 1489134646197 ,Daemon线程运行了8次
    Thread-0 is running!timestamp is 1489134646217 ,Daemon线程运行了9次
    Thread-0 is running!timestamp is 1489134646237 ,Daemon线程运行了10次
    Thread-0 is running!timestamp is 1489134646257 ,Daemon线程运行了11次
    Thread-0 is running!timestamp is 1489134646277 ,Daemon线程运行了12次
    Thread-0 is running!timestamp is 1489134646297 ,Daemon线程运行了13次
    Thread-0 is running!timestamp is 1489134646317 ,Daemon线程运行了14次
    Thread-0 is running!timestamp is 1489134646337 ,Daemon线程运行了15次
    Thread-0 is running!timestamp is 1489134646357 ,Daemon线程运行了16次
    Thread-0 is running!timestamp is 1489134646377 ,Daemon线程运行了17次
    Thread-0 is running!timestamp is 1489134646397 ,Daemon线程运行了18次
    Thread-0 is running!timestamp is 1489134646417 ,Daemon线程运行了19次
    Thread-0 is running!timestamp is 1489134646437 ,Daemon线程运行了20次
    Thread-0 is running!timestamp is 1489134646457 ,Daemon线程运行了21次
    Thread-0 is running!timestamp is 1489134646477 ,Daemon线程运行了22次
    Thread-0 is running!timestamp is 1489134646497 ,Daemon线程运行了23次
    JVM运行结束,timestamp is 1489134646511

    Process finished with exit code 0
    无论运行多少次,daemon线程中的时间戳永远小于主线程的,由此可见,当jvm中没有user线程在运行时,daemon线程也就跟着关闭了


Thread基本状态

这里写图片描述

在调用Thread实例start()方法后,基本状态为可执行状态(Runnable)、被阻塞状态(Blocked)、执行中(Running)几种状态
实例化Thread并执行start方法后,线程进入Runnable状态,此时线程尚未真正开始执行run()方法,必须等待排班器(Scheduler)插入cpu执行,线程才会执行run方法。
调用Thread.sleep()、进入synchronized前竞争对象锁定的阻断、调用wait()方法的阻断等、等待输入输出完成夜壶进入Blocked状态


安插线程

     System.out.println("主线程开始运行");        Thread threadB = new Thread(() -> {            System.out.println("Thread B开始执行...");            for (int i = 0; i < 5; i++) {                System.out.println("Thread B执行中...");            }            System.out.println("Thread B将结束...");        });        threadB.start();        threadB.join();    System.out.println("主线程将结束....");

一些Deprecated的api

1. stop方法被遗弃

1.即刻停止run()方法中剩余的全部工作,包括在catch或finally语句中,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。

2.会立即释放该线程所持有的所有的锁,导致数据得不到同步的处理,出现数据不一致的问题。

public class Main{    public static void main(String [] args) throws Exception{        TestObject testObject = new TestObject();        Thread t1 = new Thread(){            public void run(){                try {                    testObject.print("1", "2");                } catch (Exception e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        };        t1.start();        Thread.sleep(1000);        t1.stop();        System.out.println("first : " + testObject.getFirst() + " " + "second : " + testObject.getSecond());    }}class TestObject{    private String first = "ja";    private String second = "va";    public synchronized void print(String first, String second) throws Exception{        this.first = first;        Thread.sleep(10000);        this.second = second;    }    public String getFirst() {        return first;    }    public void setFirst(String first) {        this.first = first;    }    public String getSecond() {        return second;    }    public void setSecond(String second) {        this.second = second;    }}
输出first : 1 second : va

2. resume和suspend方法被遗弃

suspend()和resume()必须要成对出现,否则非常容易发生死锁。
因为suspend方法并不会释放锁,如果使用suspend的目标线程对一个重要的系统资源持有锁,那么没任何线程可以使用这个资源直到要suspend的目标线程被resumed,如果一个线程在resume目标线程之前尝试持有这个重要的系统资源锁再去resume目标线程,这两条线程就相互死锁了,也就冻结线程。

public class Main{    public static void main(String [] args) throws Exception{        TestObject testObject = new TestObject();        Thread t1 = new Thread(){            public void run(){                testObject.print();            }        };        t1.setName("A");        t1.start();        Thread.sleep(1000);        Thread t2 = new Thread(){            public void run(){                System.out.println("B已启动,但进入不到print方法中");                testObject.print();            }        };        t2.setName("B");        t2.start();    }}class TestObject{    public synchronized void print(){        if(Thread.currentThread().getName().equals("A")){            System.out.println("A 线程 独占该资源了");            Thread.currentThread().suspend();        }    }}

3. destroy方法被遗弃

当线程处于suspend状态下,此时如果调用destroy方法销毁线程,并不会释放锁,那么其他线程将不再能获取到它锁定的资源.

停止线程

stop()方法不推荐使用了,那么我如果想要认为的让线程停止怎么办呢?

public class ThreadCustom implements Runnable {    private boolean isContinue = true;    @Override    public void run() {        while (isContinue) {            System.out.println(Thread.currentThread().getName() + " is running!");        }    }    public void stop() {        isContinue = false;    }    public static void main(String[] args) throws InterruptedException {        ThreadCustom r      = new ThreadCustom();        Thread       thread = new Thread(r);        thread.start();        Thread.sleep(500);        r.stop();    }}

线程安全

  • synchronized的使用
0 0
原创粉丝点击