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



相关文章
|
3天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
16 9
|
2天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
4天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
5天前
|
Java
java小知识—进程和线程
进程 进程是程序的一次执行过程,是系统运行的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程 线程,与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比
14 1
|
Java Android开发
【Java 虚拟机原理】Java 引用类型 ( 强引用 | 软引用 | 弱引用 | 虚引用 | 静态变量 )
【Java 虚拟机原理】Java 引用类型 ( 强引用 | 软引用 | 弱引用 | 虚引用 | 静态变量 )
154 0
|
6天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
15天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
6天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
6天前
|
Java
JAVA多线程通信:为何wait()与notify()如此重要?
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是实现线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件满足时被唤醒,从而确保数据一致性和同步。相比其他通信方式,如忙等待,这些方法更高效灵活。 示例代码展示了如何在生产者-消费者模型中使用这些方法实现线程间的协调和同步。
15 3
|
6天前
|
Java UED
Java中的多线程编程基础与实践
【10月更文挑战第35天】在Java的世界中,多线程是提升应用性能和响应性的利器。本文将深入浅出地介绍如何在Java中创建和管理线程,以及如何利用同步机制确保数据一致性。我们将从简单的“Hello, World!”线程示例出发,逐步探索线程池的高效使用,并讨论常见的多线程问题。无论你是Java新手还是希望深化理解,这篇文章都将为你打开多线程的大门。