java并发原理实战(4) -- 线程的创建方式

简介: java并发原理实战(4) -- 线程的创建方式

创建线程


1dc618a0ed9580ce8bfa6facb208c08f.png


1.继承thread


执行流程:


客户端调用start()方法----private native void start0();---控制权交给jvm ----抢到资源后,执行该线程父类自定义过的自己又去重写的run()方法


实例代码:


public class Demo1 extends Thread {
    public Demo1(String name) {
        super(name);
    }
    @Override
    public void run() {
        while(!interrupted()){
            System.out.println(getName()+ " 线程执行了....");
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Demo1 demo1 = new Demo1("线程1");
        demo1.start();
    }
}


运行结果:


5d4c6812c8535adbb050f4ddf2e1bce8.png


2.实现runnable接口:


执行流程:


作为线程任务存在:线程所要做的功能 相当于给线程和任务分类,让代码更解耦 thread---new thread(target) --init方法将全局的target赋值传递过来当前线程任务---jvm 调用 ---target.run方法


1dc618a0ed9580ce8bfa6facb208c08f.png


英文翻译:


1.如果此线程是使用单独的Runnable 运行对象构造的,则将调用Runnable对象的run方法; *否则,此方法不执行任何操作并返回。


2.·Thread `的子类应重写此方法.


这里就是第1种情况,调用我们传递的runable对象的run方法。


实例代码:


public class Demo2 implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("thread running ...");
        }
    }
    public static void main(String[] args) {
        Thread thread = new Thread(new Demo2());
        thread.start();
    }
}


运行结果:

5d4c6812c8535adbb050f4ddf2e1bce8.png


3.匿名内部类的方式:


本质:只有一个线程的情况,实例不用给名字了,直接new完再用,其实也是结果上面两种方式的执行。


①重写thead类+匿名内部类


public static void main(String[] args) {
        //如果只有一个线程的话,可以使用匿名内部类
        //使用匿名内部类,相当于线程子类
        new Thread(){
            @Override
            public void run() {
                System.out.println("thread start1....");
            }
        }.start();
   }


②实现runnable+匿名内部类


//把线程任务作为参数传递
        new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println("thread start2....");
            }
        }).start();


③实现runnable+重写thead类+匿名内部类


可以这么写,但是平时不怎么干。


//把线程任务作为参数传递
        new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println("thread start2....");
            }
        }){
            @Override
            public void run() {
                System.out.println("thread start1....");
            }
        }.start();


运行结果: thread start1…


为啥尼?


这里涉及到了jvm中的方法调用动态分派的知识:也就是方法重写的原理。


实现了runable接口,作为线程任务参数传递进去,但是jvm会在执行时调用子类的run,和自己这个类的run方法没关系了,即使有target也不会被执行。


子类thread重写了run方法,根据jvm方法重写的原理,方法调用动态分派会调用子类的run方法

1dc618a0ed9580ce8bfa6facb208c08f.png


4.创建既有返回值和异常的线程


原理是啥先不用管,后面在补充吧,代码演示如下:


public class Demo4  implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        System.out.println("正在进行进行紧张的计算");
        Thread.sleep(3000);
        return 1;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //作为执行的任务
        Demo4 demo4 = new Demo4();
        //封装
        FutureTask<Integer> task = new FutureTask<>(demo4);
        //包装到thread类
        Thread thread = new Thread(task);
        thread.start();
        System.out.println("我先干点别的");
        //拿到结果
        Integer result = task.get();
        System.out.println(result);
    }
}


运行结果:


5d4c6812c8535adbb050f4ddf2e1bce8.png


运行了线程,还返回了值,牛。


5.定时器


timer


看下他的api:

1dc618a0ed9580ce8bfa6facb208c08f.png


代码演示:


public class Demo5 {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("timetask is run");
            }
        },0,1000);
    }
}


运行结果:

5d4c6812c8535adbb050f4ddf2e1bce8.png


缺点:


当一个Timer 运行多个TimerTask 时,只要其中一个TimerTask 在执行中向run 方法

外抛出了异常,则其他任务也会自动终止。


5.线程池


1dc618a0ed9580ce8bfa6facb208c08f.png

public class Demo6 {
    public static void main(String[] args) {
        //10个线程的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(10);
        for (int i=0;i<100;i++){
            //创建线程任务
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
        //停掉线程池
        threadPool.shutdown();
    }
}


运行结果:

5d4c6812c8535adbb050f4ddf2e1bce8.png

演示2:


public class Demo6 {
    public static void main(String[] args) {
        //自动创建线程池的大小,不够用就创建,用完就回收。
        ExecutorService threadPool = Executors.newCachedThreadPool();
        for (int i=0;i<100;i++){
            //创建线程任务
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
        //停掉线程池
        threadPool.shutdown();
    }
}

1dc618a0ed9580ce8bfa6facb208c08f.png


6. spring的多线程方式


pom


<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.2.RELEASE</version>
  </dependency>


Config


@Configurable
@ComponentScan("com.hfl.demo.liquidbasedemo.quartz")
@EnableAsync
public class Config  implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {//实现AsyncConfigurer接口并重写getAsyncExecutor方法,并返回一个ThreadPoolTaskExecutor,这样我们就获得了一个基于线程池TaskExecutor
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(10);
        taskExecutor.setMaxPoolSize(80);
        taskExecutor.setQueueCapacity(100);
        taskExecutor.initialize();
        return taskExecutor;
    }
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return null;
    }
}


DemoService


import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class DemoService {
    @Async
    public void a(){
        while(true){
            System.out.println("执行a方法");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    @Async
    public void b(){
        while(true){
            System.out.println("执行b方法");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


测试Test


import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
        DemoService ds = ac.getBean(DemoService.class);
        ds.a();
        ds.b();
    }
}


运行结果:循环执行

5d4c6812c8535adbb050f4ddf2e1bce8.png


7.使用lambd表达式


1dc618a0ed9580ce8bfa6facb208c08f.png

将有顺序的流分成几块,然后并行,分别执行结果。关键词是parallelStream:


演示:


/**
 * 代码简洁
 * 并发支持
 */
public class Demo7 {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(19,34, 56, 34);
        numbers.parallelStream().forEach(System.out::println);
    }
}


运行结果:


1dc618a0ed9580ce8bfa6facb208c08f.png



相关文章
|
1天前
|
Java 开发者 UED
Java中的并发编程:解锁多线程的力量
【7月更文挑战第7天】在Java的世界中,掌握并发编程是提升应用性能和响应能力的关键。本文将深入探讨如何在Java中高效地使用多线程,包括创建和管理线程、同步机制、以及避免常见的并发陷阱。我们将一起探索锁、线程池、并发集合等工具,并了解如何通过这些工具来优化程序的性能和稳定性。
|
3天前
|
存储 缓存 前端开发
Java八股文面试之多线程篇
Java八股文面试之多线程篇
14 0
Java八股文面试之多线程篇
|
3天前
|
Java
java面试之线程八锁
java面试之线程八锁
8 0
|
3天前
|
存储 SQL 安全
Java共享问题 、synchronized 线程安全分析、Monitor、wait/notify以及锁分类
Java共享问题 、synchronized 线程安全分析、Monitor、wait/notify以及锁分类
11 0
|
11天前
|
存储 测试技术
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试
17 0
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试
|
12天前
|
数据采集 Java Unix
10-多线程、多进程和线程池编程(2)
10-多线程、多进程和线程池编程
|
12天前
|
安全 Java 调度
10-多线程、多进程和线程池编程(1)
10-多线程、多进程和线程池编程
|
16天前
|
存储 Linux C语言
c++进阶篇——初窥多线程(二) 基于C语言实现的多线程编写
本文介绍了C++中使用C语言的pthread库实现多线程编程。`pthread_create`用于创建新线程,`pthread_self`返回当前线程ID。示例展示了如何创建线程并打印线程ID,强调了线程同步的重要性,如使用`sleep`防止主线程提前结束导致子线程未执行完。`pthread_exit`用于线程退出,`pthread_join`用来等待并回收子线程,`pthread_detach`则分离线程。文中还提到了线程取消功能,通过`pthread_cancel`实现。这些基本操作是理解和使用C/C++多线程的关键。
|
19天前
|
安全 Java
【极客档案】Java 线程:解锁生命周期的秘密,成为多线程世界的主宰者!
【6月更文挑战第19天】Java多线程编程中,掌握线程生命周期是关键。创建线程可通过继承`Thread`或实现`Runnable`,调用`start()`使线程进入就绪状态。利用`synchronized`保证线程安全,处理阻塞状态,注意资源管理,如使用线程池优化。通过实践与总结,成为多线程编程的专家。
|
19天前
|
Java 开发者
告别单线程时代!Java 多线程入门:选继承 Thread 还是 Runnable?
【6月更文挑战第19天】在Java中,面对多任务需求时,开发者可以选择继承`Thread`或实现`Runnable`接口来创建线程。`Thread`继承直接但限制了单继承,而`Runnable`接口提供多实现的灵活性和资源共享。多线程能提升CPU利用率,适用于并发处理和提高响应速度,如在网络服务器中并发处理请求,增强程序性能。不论是选择哪种方式,都是迈向高效编程的重要一步。