美文网首页
Java线程

Java线程

作者: Binary_r | 来源:发表于2020-11-30 13:22 被阅读0次

    一、开启线程的三种方式

    第一种,通过继承Thread类创建线程类

    public class ExtendThread extends Thread {
        private int i;
        public static void main(String[] args) {
            for(int j = 0;j < 50;j++) { 
                //调用Thread类的currentThread()方法获取当前线程
                System.out.println(Thread.currentThread().getName() + " " + j);
                if(j == 10) {
                    //创建并启动第一个线程
                    new ExtendThread().start();
                    //创建并启动第二个线程
                    new ExtendThread().start();
                }
            }
        }
    
        public void run() {
            for(;i < 100;i++) {
                //当通过继承Thread类的方式实现多线程时,可以直接使用this获取当前执行的线程
                System.out.println(this.getName() + " "  + i);
            }
        }
    }
    

    第二种,通过实现Runnable接口创建线程类

    public class ImpRunnable implements Runnable {
        private int i;
        @Override
        public  void run() {
            for(;i < 50;i++) {  
                //当线程类实现Runnable接口时,要获取当前线程对象只有通过Thread.currentThread()获取
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
        }
     
        public static void main(String[] args) {
            for(int j = 0;j < 30;j++) {
                System.out.println(Thread.currentThread().getName() + " " + j);
                if(j == 10) {
                    ImpRunnable thread_target = new ImpRunnable();
                    //通过new Thread(target,name)的方式创建线程
                    new Thread(thread_target,"线程1").start();
                    new Thread(thread_target,"线程2").start();
                }
            }
        }
    }
    

    第三种,通过Callable和Future接口创建线程

    public class ThirdThreadImp {
        
        public static void main(String[] args) {
            //这里call()方法的重写是采用lambda表达式,没有新建一个Callable接口的实现类
            FutureTask<Integer> task =  new FutureTask<Integer>((Callable<Integer>)()->{
                int i = 0;
                for(;i < 50;i++) {
                    System.out.println(Thread.currentThread().getName() + 
                            "  的线程执行体内的循环变量i的值为:" + i); 
                }
                //call()方法的返回值
                return i;
            });
            
            for(int j = 0;j < 50;j++) {
                System.out.println(Thread.currentThread().getName() + 
                        " 大循环的循环变量j的值为:" + j);
                if(j == 20) {
                    new Thread(task,"有返回值的线程").start();
                }
            }
            try {
                System.out.println("子线程的返回值:" + task.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    二、三种创建方式对比

    通过继承Thread类实现多线程:
    优点:
    1、实现起来简单,而且要获取当前线程,无需调用Thread.currentThread()方法,直接使用this即可获取当前线程;
    缺点:
    1、线程类已经继承Thread类了,就不能再继承其他类;
    2、多个线程不能共享同一份资源(如前面分析的成员变量 i );

    通过实现Runnable接口或者Callable接口实现多线程:
    优点:
    1、线程类只是实现了接口,还可以继承其他类;
    2、多个线程可以使用同一个target对象,适合多个线程处理同一份资源的情况。
    缺点:
    1、通过这种方式实现多线程,相较于第一类方式,编程较复杂;
    2、要访问当前线程,必须调用Thread.currentThread()方法。

    三、线程的五种状态

    1、创建状态
    2、就绪状态
    3、运行状态
    4、阻塞状态
    5、死亡状态

    守护线程
    线程分为用户线程和守护线程
    虚拟机必须确保用户线程执行完毕
    虚拟机不必等待守护线程执行完毕,如:日志、内存监控、垃圾回收

    四、同步方法

    synchronized方法和synhronized同步块
    synchronized方法控制着对对象的访问,每个对象对应着一把锁,需要方法返回才释放锁

    synhronized同步块
    synhronized (Obj) {}
    Obj称为同步监视器
    Obj可以是任何对象,但是推荐使用共享资源作为同步监视器
    同步方法中无需制定同步监视器,因为同步方法的同步监视器就是this,就是这个对象本身
    

    锁Lock

    定义锁private final ReentrantLock lock = new ReentrantLock();
    加锁:lock.lock();
    解锁:lock.unlock();

    推荐使用try{}finally{}的方式进行加锁解锁

    synchronized与Lock的对比

    • Lock是显式锁(手动开启和关闭),synchronized是隐式锁,出了作用域会自动释放
    • Lock只有代码块锁,synchronized有代码块锁和方法锁
    • 使用Lock锁,JVM将花费较少时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
    • 优先使用顺序
      Lock -> 同步代码块 -> 同步方法

    五、线程协作

    生产者消费者

    相关文章

      网友评论

          本文标题:Java线程

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