关于多线程,看了许多大佬的帖子,自己也思索了很久,虽然许多地方还是不清楚,但还是有必要记录一下自己的所得。

首先贴上状态图:

(1)New:创建一个线程时,线程进入这个状态

(2)Runnable:调用start()后,进入这个状态

(3)Running:执行run()时,进入这个状态

(4)Blocked:阻塞状态,分3种情况

  • 等待阻塞:调用wait()后进入等待阻塞。
  • 同步阻塞:当多个线程同时执行某一对象的同步代码块时,只有一个线程能执行,其余线程进入阻塞状态。
  • 其他阻塞:调用sleep进入"睡眠“,join()另一个线程先执行,或有I/O请求进入其他阻塞。

一.建立线程的3种形式

(1)直接继承Thread创建

public class Test
{public static void main(String[] args){MyThread mt=new MyThread();mt.start();}
}
class MyThread extends Thread
{@Overridepublic void run() {System.out.println("这是一个新线程");}
}

(2)实现Runnable接口

public class Test
{public static void main(String[] args){MyThread mt=new MyThread();Thread t=new Thread(mt);t.start();}
}
class MyThread implements Runnable
{@Overridepublic void run() {System.out.println("这是一个新线程");}
}

(3)实现Callable接口,用FutureTask进行封装

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test
{public static void main(String[] args){Callable mt=new MyThread();FutureTask ft=new FutureTask(mt);Thread t=new Thread(ft);t.start();try {System.out.println(ft.get());}catch (Exception e){e.printStackTrace();}}
}
class MyThread implements Callable
{@Overridepublic String call() {System.out.println("这是一个新线程");return "测试结束";}
}

在这种实现方式中,线程可以具备返回值。

二.线程的三种阻塞状态

在将阻塞之前,有必要了解一下synchronized关键字的意思,用synchronized修饰的代码块代表着线程同步,假如一个类A有3个同步方法,有一对象a是A的实例,如果有一线程正在执行对象a的某一个同步方法,那么其余任何线程都不能执行对象a的同步方法。专业点说就是当前执行的线程获得了对象a的"同步锁",其他线程要去执行a的同步方法必须先去获得"同步锁",但发现”同步锁“没有释放,因此只能等着当前执行的线程执行完并且释放”同步锁“。

(1)sleep()阻塞,join()阻塞和I/O阻塞

sleep()方法使线程进入"睡眠"状态,但在睡眠状态中不会释放同步锁,示例:

public class Test
{public static void main(String[] args) throws InterruptedException{int i=0;ClassTest ct=new ClassTest();ThreadOne t1=new ThreadOne(ct);Thread.sleep(1000);i++;ThreadTwo t2=new ThreadTwo(ct);while (true){Thread.sleep(1000);System.out.println(++i);}}
}
class ThreadOne extends Thread
{public ClassTest ct;public ThreadOne(ClassTest ct){this.ct=ct;start();}@Overridepublic void run() {try {ct.printOne();}catch (InterruptedException e) {e.printStackTrace();}}
}
class ThreadTwo extends Thread
{public ClassTest ct;public ThreadTwo(ClassTest ct){this.ct=ct;start();}@Overridepublic void run() {ct.printTwo();}
}
class ClassTest
{public synchronized void printOne() throws InterruptedException{Thread.sleep(5000);System.out.println("--------");}public synchronized void printTwo(){System.out.println("++++++++");}
}

输出如下:

在这个代码中,用两个线程t1和t2去分别运行ct对象的printOne()和printTwo()方法,t2比t1后1秒运行,结果是在第5秒时,两个依次输出,在printTwo()中,没有设置线程"睡眠"但依旧等到printOne()输出后才输出,证明sleep()不会释放同步锁。

join()方法的作用是等待另一线程执行完,在执行自身线程。示例:

public class Test
{public static void main(String[] args) throws InterruptedException{ThreadOne t1=new ThreadOne();t1.start();t1.join();while (true){System.out.println(0);}}
}
class ThreadOne extends Thread {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {System.out.println(Thread.currentThread().getName() + "  " + i);}}
}

输出如下:

截图不能截完,自行测试,当线程t1join()之后,直到t1执行完才开始执行主线程,主线程阻塞,相当于t1线程与主线程变成了顺序执行。

I/O阻塞直接看示例

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;public class Test
{public static void main(String[] args){try {PipedInputStream in = new PipedInputStream();PipedOutputStream out = new PipedOutputStream(in);ThreadIn read = new ThreadIn(in);ThreadOut write = new ThreadOut(out);write.start();read.start();}catch (IOException e){e.printStackTrace();}}
}
class ThreadIn extends Thread
{PipedInputStream in;public ThreadIn(PipedInputStream in){this.in=in;}@Overridepublic void run() {try {while (true) {in.read(new byte[1024]);System.out.println("读一次");}}catch (IOException e){e.printStackTrace();}}
}
class ThreadOut extends Thread
{PipedOutputStream out;public ThreadOut(PipedOutputStream out){this.out=out;}@Overridepublic void run() {try {while (true){out.write("abcde".getBytes());sleep(2000);System.out.println("等待2秒");}}catch (Exception e){e.printStackTrace();}}
}

输出如下:

"读线程"每次都要等"写线程"写入数据之后才读取,当没有数据读取的时候就阻塞。

(2)等待阻塞与同步阻塞

等待阻塞是由wait()引发的,wait()的作用是将当前线程挂起,和sleep()作用相似,但wait()会释放同步锁,当wait()挂起时,其余线程也可以获得当前对象的”同步锁“,notify和notifyAll可以解除由wait()挂起的线程,它们都必须存在于synchronized块中,且必须作用于同一对象。示例如下:

import java.io.IOException;public class Test
{public static void main(String[] args){try {ClassTest ct = new ClassTest();ThreadOne t1 = new ThreadOne(ct);ThreadTwo t2 = new ThreadTwo(ct);t1.start();Thread.sleep(1000);t2.start();while (true){int ch=System.in.read();if(ch=='a'){System.out.println("按下A键,改变ct.blag=true");ct.blag=true;}if(ch=='b'){System.out.println("按下B键,改变ct.blag=false");ct.blag=false;Thread.sleep(1000);System.out.println(ct.blag);}}}catch (InterruptedException e){e.printStackTrace();}catch (IOException e){e.printStackTrace();}}
}
class ThreadOne extends Thread
{ClassTest ct;public ThreadOne(ClassTest ct){this.ct=ct;}@Overridepublic void run() {ct.print();}
}
class ThreadTwo extends Thread
{ClassTest ct;public ThreadTwo(ClassTest ct){this.ct=ct;}@Overridepublic void run() {ct.waitPrint();}
}
class ClassTest
{volatile boolean blag=false;public synchronized void print(){int i=0;System.out.println("print占用");try {while (true) {while (!blag) {Thread.sleep(3000);System.out.println(i++);}System.out.println("print释放同步锁");wait();System.out.println("结束wait");}}catch (InterruptedException e){e.printStackTrace();}}public synchronized void waitPrint(){System.out.println("waitPrint获得同步锁");while (blag) {}System.out.println("waitPrint结束");notify();}
}

输出如下:

在这个测试用例里面,t1线程最开始获得同步锁,并每隔3秒输出一个i值,t2线程阻塞,等待t1执行完,主线程改变blag状态使得t1线程和t2线程可以释放同步锁。等待阻塞就是当线程调用wait方法后,自身会"挂起",进入阻塞状态,但会释放同步锁,此例中t1在"挂起"后t2可以调用ct对象的同步方法。同步阻塞即多个线程同时调用一个对象的同步方法,只有一个线程能执行,此例中t1先调用print,t2只有等t1释放同步锁后才能执行。

注意:blag必须声明为volatile,每个线程都有自己的缓存(线程栈),它们从主存拿取数据,如果不声明为volatile,即便主线程改变了blag的值,t2线程使用的也可能时自己线程本身缓存里面的blag值。

Thinking in java:多线程相关推荐

  1. Java 多线程的基本方式

    Java 多线程的基本方式 基础实现两种方式: 通过实现Callable 接口方式(可得到返回值):

  2. Java多线程读取本地照片为二进制流,并根据系统核数动态确定线程数

    Java多线程读取图片内容并返回 1. ExecutorService线程池 2. 效率截图 3. 源码 1. ExecutorService线程池 ExecutorService线程池,并可根据系统 ...

  3. Java多线程,Thread,Runnable,Callable Task,Future<Task>,CompletionService

    一.Java多线程的方法 1. 继承 Thread 2. 实现 Runnable 3. 实现 Callable 可以有返回值 package com.test;import java.util.Arr ...

  4. 【收藏】Java多线程/并发编程大合集

    (一).[Java并发编程]并发编程大合集-兰亭风雨    [Java并发编程]实现多线程的两种方法    [Java并发编程]线程的中断    [Java并发编程]正确挂起.恢复.终止线程    [ ...

  5. 40个Java多线程问题总结

    (转) 这篇文章作者写的真是不错 40个问题汇总 1.多线程有什么用? 一个可能在很多人看来很扯淡的一个问题:我会用多线程就好了,还管它有什么用?在我看来,这个回答更扯淡.所谓"知其然知其所 ...

  6. Java多线程编程实战:模拟大量数据同步

    背景 最近对于 Java 多线程做了一段时间的学习,笔者一直认为,学习东西就是要应用到实际的业务需求中的.否则要么无法深入理解,要么硬生生地套用技术只是达到炫技的效果. 不过笔者仍旧认为自己对于多线程 ...

  7. Java多线程学习处理高并发问题

    在程序的应用程序中,用户或请求的数量达到一定数量,并且无法避免并发请求.由于对接口的每次调用都必须在返回时终止,因此,如果接口的业务相对复杂,则可能会有多个用户.调用接口时,该用户将冻结. 以下内容将 ...

  8. Java多线程常见面试题及答案汇总1000道(春招+秋招+社招)

    Java多线程面试题以及答案整理[最新版]Java多线程高级面试题大全(2021版),发现网上很多Java多线程面试题都没有答案,所以花了很长时间搜集,本套Java多线程面试题大全,汇总了大量经典的J ...

  9. java多线程编程01---------基本概念

    一. java多线程编程基本概念--------基本概念 java多线程可以说是java基础中相对较难的部分,尤其是对于小白,次一系列文章的将会对多线程编程及其原理进行介绍,希望对正在多线程中碰壁的小 ...

  10. Java多线程的同步机制(synchronized)

    一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个 ...

最新文章

  1. JQuery中全局变量和局部变量的理解
  2. 腾讯云数据库副总监:图数据库好在哪?该用在哪?
  3. oracle存储过程调用游标例子
  4. 纯JS制作的窗户雨滴效果
  5. IntelliJ IDEA常用的快捷键(代码提示/注释代码/加入类注释和方法注释Javadoc)
  6. JS学习记录(BOM部分)
  7. Netty技术细节源码分析-Recycler对象池原理分析
  8. android之NDK version was not found
  9. 设计模式之(Facade)外观模式
  10. 数据库及对应数据文件使用查询
  11. 【渝粤题库】陕西师范大学163208 饭店管理 作业
  12. 使用 Transformer 序列到序列的钢琴转录
  13. html绘制直角坐标系,几何画板如何画直角坐标系并描点
  14. linux meld 中文乱码,linux下paste、diff、meld的使用
  15. 使用Aspose.Words设置word文档多倍行距
  16. 什么是企业oa办公系统登录入口?oa办公系统哪家好?
  17. 软考 - 10 智能家居管理系统
  18. 汇编语言标志位 含义 NV UP EI NG NZ AC PE CY
  19. ps打开笔压仍没有效果
  20. spring事务失效了? @Transactional不管用了 ?看看这些@Transation的坑

热门文章

  1. 10句民间俗语,感悟古人智慧
  2. 详细实现yolov5测试丶自己数据集训练测试丶Tensorrt加速优化(完 结 !)+ 跟踪(补充)
  3. 自由到底意味着什么(一)我不要做什么就能够不做什么
  4. opencv 照片动漫风格
  5. 算法手撕代码111~120
  6. 技术能力发展的布朗运动
  7. 画动漫女孩的方法,教你好看的动漫女孩怎么画
  8. Sql Server 中 mdf和ldf
  9. 视觉SLAM十四讲 报错 Could not find a configuration file for package “OpenCV“ that is compatible with reques
  10. Elasticsearch基本概念