线程详解

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("主线程将结束...."); 

输出为:
主线程开始运行
Thread B开始执行…
Thread B执行中…
Thread B执行中…
Thread B执行中…
Thread B执行中…
Thread B执行中…
Thread B将结束…
主线程将结束….

从上面的代码中,我们可以看到存在两个线程:主线程和线程Thread B

主线程调用线程Thread B的Join方法,导致主线程阻塞,直到Thread B线程执行完毕,才返回到主线程中。

简单理解,在主线程中调用Thread B.join(),也就是在主线程中加入了Thread B线程的代码,必须让Thread B线程执行完毕之后,主线程(调用方)才能j正常执行。


一些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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值