java多线程

并发与并行

并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行

并行:一组程序按独立异步的速度执行,无论从微观还是宏观,程序都是一起执行的。

对比:并发是指:在同一个时间段内,两个或多个程序执行,有时间上的重叠(宏观上是同时,微观上仍是顺序执行)

进程与线程

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础

线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

java的线程

java多线程机制

多线程是指一个应用程序同时存在几个执行体,按照几条不同的执行线索共同工作的情况。java多线程机制,它使得编程人员可以很方便的开发出具有多线程功能、能同时处理多个任务的强大应用程序。java内置对多线程的支持,java虚拟机可以快速的从一个线程切换到另一个线程。这些线程的轮流执行使得每个线程都有机会使用cpu资源。

java的主线程

每个java程序都含有一个线程,那就是主线程(main线程)。Java应用程序都是从主类main方法执行的,当jvm加载代码,发现卖弄方法之后,就会启动一个线程,这个线程就是主线程,负责执行main方法。如果在主线程里面创建其他线程,就会在主线程和其他线程来回切换,直到其他所有线程结束才会结束主线程。

线程的生命周期

  • 运行

    线程创建之后只占有了内存资源,在JVM管理的线程中并没有刚刚创建的这个线程,只有这个线程调用start()方法后,JVM才知道有一个新线程进入队列等待cpu调用。

  • 中断原因(4种)

    • jVM把cpu资源切换给其他线程。
    • 线程使用cpu期间,执行了sleep(int millsecond)方法,使当前线程进入休眠状态,调用该方法之后会立即让出cpu,经过参数millsecond指定的毫秒后,重新加入队列等待cpu。

      -使用cpu期间,执行了wait()方法,使得当前进程进入等待状态,这个等待个sleep()不同,这个等待需要其他线程调用notify()方法唤醒该线程,此线程才会重新进入队列,等待cpu。

      线程使用cpu期间,执行了某个操作进入阻塞状态,例如(读、写、打印等),只有这些造成阻塞的原因完成,这个线程才会进入队列,等待cpu。

创建线程(3种)

继承Thread类实现线程创建

  • 一种是创建一个类继承Thread类,这种继承可以重复使用!
  • 一种是直接使用匿名内部类继承,这种类型只能使用一次,每次使用都要重新创建
  • 不论哪种都需要重写run()方法,并且在定义之后调用start()方法,把这个线程调入线程队列等待调用。

下面我们使用匿名内部类创建一个打印100以内的奇数线程,使用类继承Thread类打印100内的偶数线程。

package hello;

public class Hello {
public static void main(String[] args) {
Thread1 thread1 = new Thread1();
Thread thread = new Thread() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 1) {
//打印线程名,线程名是从0开始的
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}; thread1.start();
thread.start(); }
} class Thread1 extends Thread{
@Override
public void run() {
super.run();
for(int i=0;i<100;i++){
if (i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}

方法说明

start()启动当前线程;调用当前线程的run()方法

run():需要重写Thread类中的此方法,将创建线程需要执行的操作声明在此方法中

currentThread():返回执行当前代码的线程

getName():获取当前线程的名字

setName(String name):设置当前线程的名字

yield():释放当前CPU的执行权

join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完之后,线程a在结束阻塞状态

sleep(int millitime):让当前线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒时间内,当前进程是阻塞状态

isAlive():判断当前线程是否存活(线程执行完之前都是存活的)

实现Runnable接口

  • 我们还是创建两个线程,一个打印奇数,一个打印偶数,但是有一个线程每次调用会睡眠(阻塞)10ms。
  • 使用实现接口Runnable方法,必须重写run()方法。
package hello;

public class Hello {
public static void main(String[] args) {
Thread thread = new Thread(new MyThread1());
/*
Thread thread = new Thread(new MyThread1());
就相当于 ,就是创建实现类的对象,再把这个对象用Thread()构造器的方法创建
MyThread1 myThread1 = new MyThread1();
Thread thread = new Thread(myThread1);
*/
Thread thread1 = new Thread(new MyThread2());
thread.start();
thread1.start(); }
} class MyThread1 implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++) {
if (i % 2 == 1) {
System.out.println(Thread.currentThread().getName() + ":" + i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
} }
}
}
} class MyThread2 implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ":" + i); }
}
}
}

开发中,优先选择实现Runnable接口的方式创建线程

原因:

实现Runnable接口的方式没有类的单继承性的局限性(一个类只能继承一个父类,继承了Thread类就不能在继承其他类了)

实现Runnable接口的方式更适合来处理多个线程之间有共享数据的情况

实现Callable接口

Runnable接口是没有返回值的 Callable有返回值,可以抛出异常

Thread类并不接受Callable对象。可以使用FutureTask类实现Runnable接口和Future接口

Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

Java的类是单继承的设计,如果采用继承Thread的方式实现多线程,则不能继承其他的类,采用接口能够更好的实现数据共享

FutureTask有两个构造函数,一个以Callable为参数,另外一个以Runnable为参数。

我理解的就是通过FutureTask把Callable变成通过Runnable接口创建的,因为FutureTask继承了Runnable接口。主要原因是Thread类不接受Callable创建,但是接受Runnable创建的线程。

package hello;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask; public class Hello {
public static void main(String[] args) throws Exception { MyThread1 myThread1 = new MyThread1();
FutureTask<Integer> futureTask = new FutureTask<>(new MyThread1());
new Thread(futureTask).start();//开启线程
System.out.println(futureTask.get());//获取返回值 }
} class MyThread1 implements Callable<Integer> { @Override
public Integer call() throws Exception {
int count = 0;
for (int i = 1;i<100;i++){
if (i%3==0){
count++;
}
}
return count;
}
}

线程池

线程池的执行过程

  • 实例
package hello;

import java.util.concurrent.*;

public class Hello {
public static void main(String[] args) throws Exception { //创建线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4, 5, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(2),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("myThread");
return thread;
}
},
new ThreadPoolExecutor.AbortPolicy()); //threadPoolExecutor.submit();
threadPoolExecutor.execute(new MyThread());//提交任务
threadPoolExecutor.shutdown();//关闭线程池 }
} class MyThread implements Runnable{ @Override
public void run() {
for (int i=0;i<10;i++){
System.out.println(i);
}
}
}

Java多线程【三种实现方法】的更多相关文章

  1. java list三种遍历方法性能比較

    从c/c++语言转向java开发,学习java语言list遍历的三种方法,顺便測试各种遍历方法的性能,測试方法为在ArrayList中插入1千万条记录,然后遍历ArrayList,发现了一个奇怪的现象 ...

  2. java list三种遍历方法性能比较

    从c/c++语言转向java开发,学习java语言list遍历的三种方法,顺便测试各种遍历方法的性能,测试方法为在ArrayList中插入1千万条记录,然后遍历ArrayList,发现了一个奇怪的现象 ...

  3. JAVA多线程三种实现方式

    JAVA多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没 ...

  4. Java 多线程 三种实现方式

    Java多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没 ...

  5. java多线程三种方式

    java多线程都有几种方式 有三种: (1)继承Thread类,重写run函数 创建: class xx extends Thread{ public void run(){ Thread.sleep ...

  6. Java List /ArrayList 三种遍历方法

    java list三种遍历方法性能比较http://www.cnblogs.com/riskyer/p/3320357.html JAVA LIST 遍历http://blog.csdn.net/lo ...

  7. 2017.10.25 Java List /ArrayList 三种遍历方法

    java list三种遍历方法性能比较 学习java语言list遍历的三种方法,顺便测试各种遍历方法的性能,测试方法为在ArrayList中插入记录,然后遍历ArrayList,测试代码如下: pac ...

  8. Java中Map的三种遍历方法

    Map的三种遍历方法: 1. 使用keySet遍历,while循环: 2. 使用entrySet遍历,while循环: 3. 使用for循环遍历.   告诉您们一个小秘密: (下↓面是测试代码,最爱看 ...

  9. java数组中的三种排序方法中的冒泡排序方法

    我记得我大学学java的时候,怎么就是搞不明白这三种排序方法,也一直不会,现在我有发过来学习下这三种方法并记录下来. 首先说说冒泡排序方法:冒泡排序方法就是把数组中的每一个元素进行比较,如果第i个元素 ...

  10. SuperDiamond在JAVA项目中的三种应用方法实践总结

    SuperDiamond在JAVA项目中的三种应用方法实践总结 1.直接读取如下: @Test public static void test_simple(){ PropertiesConfigur ...

随机推荐

  1. shell——trap捕捉信号(附信号表)

    trap捕捉信号有三种形式 第一种:trap "commands" signal-list 当脚本收到signal-list清单内列出的信号时,trap命令执行双引号中的命令. 例 ...

  2. pm2 部署 vue

    链接:我整理了一个网站, 用来介绍一些有意思和实用工具的网站, 我没有打包, 直接甩上去了 因为vue是用 npm run dev 来运行的, 你用pm2 npm run dev 是错误的 需要加上- ...

  3. MXNet学习:预测结果-识别单张图片

    用到了model里的FeedForward.load和predict import os import mxnet as mx import numpy as np import Image from ...

  4. Solution -「CF 855G」Harry Vs Voldemort

    \(\mathcal{Description}\)   Link.   给定一棵 \(n\) 个点的树和 \(q\) 次加边操作.求出每次操作后,满足 \(u,v,w\) 互不相等,路径 \((u,w ...

  5. C#随机打乱列表List元素顺序

    C#随机打乱列表List项目顺序 以下泛型扩展方法,实现了随机打乱泛型列表List<T>的功能 public static List<t> DisorderItems<t ...

  6. application.yaml配置文件

    spring boot还支持yaml格式的配置文件.这种格式文件是JSON超集文件格式,其以数据为中心,扩展名可是是yml和yaml. yaml格式文件以key/value的格式配置属性,使用缩进控制 ...

  7. mongodb4.x 集群搭建

    下载包 官网选择合适的操作系统版本下载tgz包 https://www.mongodb.com/download-center/community 部署结构 集群结构 典型的三分片Mongo集群如下图 ...

  8. ios开发 将json格式数据上传服务器

    看了一些大小牛的资料其实就3步 1.使用post 请求 ,因为get是不能上传的 2.设置请求类型 , 讲你的json数据上传 3.向服务器发送数据按照下面示例代码,就差不多了 1 // 1.创建请求 ...

  9. scrapy的介绍、组件、数据流

    scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,我们只需要实现少量代码,就能够快速的抓取到数据内容. scrapy使用了twisted异步网络框架来处理网络通讯,来加快我们的下载速 ...

  10. 在Linux发行版上使用7zip的方法

    学习如何在 Ubuntu 和其他 Linux 发行版中安装和使用 7zip 7zip介绍 7Zip(更适当的写法是 7-Zip)是一种在 Windows 用户中广泛流行的归档格式.一个 7Zip 归档 ...