美文网首页
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