Thinking in java:多线程
关于多线程,看了许多大佬的帖子,自己也思索了很久,虽然许多地方还是不清楚,但还是有必要记录一下自己的所得。
首先贴上状态图:
(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:多线程相关推荐
- Java 多线程的基本方式
Java 多线程的基本方式 基础实现两种方式: 通过实现Callable 接口方式(可得到返回值):
- Java多线程读取本地照片为二进制流,并根据系统核数动态确定线程数
Java多线程读取图片内容并返回 1. ExecutorService线程池 2. 效率截图 3. 源码 1. ExecutorService线程池 ExecutorService线程池,并可根据系统 ...
- Java多线程,Thread,Runnable,Callable Task,Future<Task>,CompletionService
一.Java多线程的方法 1. 继承 Thread 2. 实现 Runnable 3. 实现 Callable 可以有返回值 package com.test;import java.util.Arr ...
- 【收藏】Java多线程/并发编程大合集
(一).[Java并发编程]并发编程大合集-兰亭风雨 [Java并发编程]实现多线程的两种方法 [Java并发编程]线程的中断 [Java并发编程]正确挂起.恢复.终止线程 [ ...
- 40个Java多线程问题总结
(转) 这篇文章作者写的真是不错 40个问题汇总 1.多线程有什么用? 一个可能在很多人看来很扯淡的一个问题:我会用多线程就好了,还管它有什么用?在我看来,这个回答更扯淡.所谓"知其然知其所 ...
- Java多线程编程实战:模拟大量数据同步
背景 最近对于 Java 多线程做了一段时间的学习,笔者一直认为,学习东西就是要应用到实际的业务需求中的.否则要么无法深入理解,要么硬生生地套用技术只是达到炫技的效果. 不过笔者仍旧认为自己对于多线程 ...
- Java多线程学习处理高并发问题
在程序的应用程序中,用户或请求的数量达到一定数量,并且无法避免并发请求.由于对接口的每次调用都必须在返回时终止,因此,如果接口的业务相对复杂,则可能会有多个用户.调用接口时,该用户将冻结. 以下内容将 ...
- Java多线程常见面试题及答案汇总1000道(春招+秋招+社招)
Java多线程面试题以及答案整理[最新版]Java多线程高级面试题大全(2021版),发现网上很多Java多线程面试题都没有答案,所以花了很长时间搜集,本套Java多线程面试题大全,汇总了大量经典的J ...
- java多线程编程01---------基本概念
一. java多线程编程基本概念--------基本概念 java多线程可以说是java基础中相对较难的部分,尤其是对于小白,次一系列文章的将会对多线程编程及其原理进行介绍,希望对正在多线程中碰壁的小 ...
- Java多线程的同步机制(synchronized)
一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个 ...
最新文章
- JQuery中全局变量和局部变量的理解
- 腾讯云数据库副总监:图数据库好在哪?该用在哪?
- oracle存储过程调用游标例子
- 纯JS制作的窗户雨滴效果
- IntelliJ IDEA常用的快捷键(代码提示/注释代码/加入类注释和方法注释Javadoc)
- JS学习记录(BOM部分)
- Netty技术细节源码分析-Recycler对象池原理分析
- android之NDK version was not found
- 设计模式之(Facade)外观模式
- 数据库及对应数据文件使用查询
- 【渝粤题库】陕西师范大学163208 饭店管理 作业
- 使用 Transformer 序列到序列的钢琴转录
- html绘制直角坐标系,几何画板如何画直角坐标系并描点
- linux meld 中文乱码,linux下paste、diff、meld的使用
- 使用Aspose.Words设置word文档多倍行距
- 什么是企业oa办公系统登录入口?oa办公系统哪家好?
- 软考 - 10 智能家居管理系统
- 汇编语言标志位 含义 NV UP EI NG NZ AC PE CY
- ps打开笔压仍没有效果
- spring事务失效了? @Transactional不管用了 ?看看这些@Transation的坑
热门文章
- 10句民间俗语,感悟古人智慧
- 详细实现yolov5测试丶自己数据集训练测试丶Tensorrt加速优化(完 结 !)+ 跟踪(补充)
- 自由到底意味着什么(一)我不要做什么就能够不做什么
- opencv 照片动漫风格
- 算法手撕代码111~120
- 技术能力发展的布朗运动
- 画动漫女孩的方法,教你好看的动漫女孩怎么画
- Sql Server 中 mdf和ldf
- 视觉SLAM十四讲 报错 Could not find a configuration file for package “OpenCV“ that is compatible with reques
- Elasticsearch基本概念