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. 线性结构和非线性结构、稀疏数组、队列、链表(LinkedList)

    一.线性结构和非线性结构 线性结构: 1)线性绪构作为最常用的数据结构,其特点是数据元素之间存在一对一的线性关系 2)线性结构有两种不同的存储结构,即顺序存储结构和链式存储结构.顺序存储的线性表称为顺 ...

  2. 当gitlab的数据库坏了,或者其他的组件坏了,修复教程。

    一般企业的gitlab都承载着多个项目的源码和提交记录 如果gitlab的数据库 PostgreSQL 坏掉了,基本很难修复,那这是不是意味着源码丢失了呢. 本文章只针对 gitlab传统存储方式的修 ...

  3. git忽略文件权限检查

    如题  每个人本地设置不同 系统不同  环境不同  很有可能在团队开发的时候进行 不同文件权限的设置 但是如果大家都把这种权限的设置传上去 那么所有人的就都乱的 如果要去掉的话 第一步 进入这个项目的 ...

  4. Eclipse插件开发demo

    一.安装 1. 下载安装JDk 2. 下载安装PDE(Plugin-in Development Environment) 访问eclipse官网,点击Download,选择Download Pack ...

  5. Java诊断神器:Arthas常用功能

    最新原文:https://www.cnblogs.com/uncleyong/p/14944401.html Arthas是Alibaba开源的Java诊断工具,功能很强大,它是通过Agent方式来连 ...

  6. python https 无法访问 SSLError("Can\'t connect to HTTPS URL because the SSL module is not available

    1,需要检查python 安装的时候是否支持 https 进入python 环境,import ssl 如果正常导入就可以使用https,不能导入就需要进入下一步. 2,查看系统是否安装了openss ...

  7. [题解]第十一届北航程序设计竞赛预赛——F.序列

    题目描述 (1,--,n)的一个排列S,定义其对应的权值F[S]为:将S划分为若干段连续子序列,每个子序列都是上升序列,F[S]的值等于能划分出的最小段数. 求n的全排列的F[S]的和,答案mod(1 ...

  8. MM32F0020 GPIO驱动LED灯(MM32F0020 GPIO Toggle)

    目录: 1.MM32F0020简介 2.MM32F0020系统时钟配置 3.MM32F0020的GPIO外设配置及其初始化 4.使用官网的Systick定时器做延时 5.MM32F0020 GPIO驱 ...

  9. Oracle之表和字段的注释

    给表名加上注释 --给表名加上注释的语法结构 --语法结构:COMMENT ON TABLE 英文表名 IS '中文注释' COMMENT ON TABLE DEPT IS '部门表'; 给字段加上注 ...

  10. Spark学习笔记(详细)

    Spark Core 第1章 Spark 概述 Spark是一种基于内存的快速.通用.可扩展的大数据分析计算引擎 Spark和Hadoop 的根本差异是多个作业之间的数据通信问题: Spark多个作业 ...