java——多线程知识点大总结
1:理解线程的概念之前,我们有必要先理解一下进程的概念
程序(Program)是为实现特定目标或解决特定问题而用计算机语言(比如Java语言)编写的命令序列的集合。
进程指一个程序的一次执行过程


2:线程
线程又称为轻量级进程,线程是一个程序中实现单一功能的一个指令序列,是一个程序的单个执行流,存在于进程中,是一个进程的一部分。线程不能单独运行,必须在一个进程之内运行。





线程的特点

线程和进程

如何自定义线程类



线程中的进程



线程中的常用方法

import java.util.Date;
class TimeThread extends Thread{
@Override
public void run() {
for(int i=0;i<=2; i++){
System.out.println("时间线程:"+new Date());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class CounterThread extends Thread {
private TimeThread timeThread;
public CounterThread(TimeThread timeThread){
this.timeThread = timeThread;
}
@Override
public void run() {
for(int i=1;i<=3; i++){
if(i==2){
try {
timeThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("计数器线程:"+i);
}
}
}
public class Program {
public static void main(String[] args) {
TimeThread timeThread = new TimeThread();
timeThread.start();
new CounterThread(timeThread).start();
}
}
注意:线程对象在调用join方法前必须先调用start方法,否则该线程永远不会进入执行状态。

import java.text.SimpleDateFormat;
import java.util.Date; class TimeThread extends Thread { public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss:sss");
String beforeTime = sdf.format(new Date());
System.out.println("beforeTime:"+beforeTime);
try {
sleep(30000);// 30秒后执行后面代码
} catch (Exception e) {
System.out.println("程序捕获了InterruptedException异常!");
}
String afterTime = sdf.format(new Date());
System.out.println("afterTime:"+afterTime);
}
} public class Program {
public static void main(String[] args) {
TimeThread timeThread = new TimeThread();
timeThread.start();
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
timeThread.interrupt();
}
}

class CounterThread extends Thread {
Object lockObj;
public CounterThread(Object lockObj) {
this.lockObj = lockObj;
}
@Override
public void run() {
synchronized (lockObj) {
System.out.println("计数器线程正在执行......");
try {
lockObj.wait();//当线程执行该行代码后,线程进入阻塞状态;但由于10秒后主线程执行了“counterThread.interrupt();”代码使得该线程阻塞状态结束
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Test {
public static void main(String[] args) {
Object lockObj = new Object();
CounterThread counterThread = new CounterThread(lockObj);
counterThread.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
counterThread.interrupt();
}
}
import java.util.Date;
class TimeThread extends Thread{
@Override
public void run() {
for(int i=0;i<=2; i++){
System.out.println("时间线程:"+new Date());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class CounterThread extends Thread {
private TimeThread timeThread;
public CounterThread(TimeThread timeThread){
this.timeThread = timeThread;
}
@Override
public void run() {
for(int i=1;i<=3; i++){
if(i==2){
try {
timeThread.join();
} catch (InterruptedException e) {
System.out.println("计数器线程提前结束阻塞状态");
}
}
System.out.println("计数器线程:"+i);
}
}
}
public class Program {
public static void main(String[] args) {
TimeThread timeThread = new TimeThread();
timeThread.start();
CounterThread counterThread = new CounterThread(timeThread);
counterThread.start();
try {
Thread.sleep(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
counterThread.interrupt();//计数器线程执行该行代码后进入阻塞状态,时间线程至少需要消耗30秒才能结束,而15秒后计数器线程调用了interrupt方法致使该计数器线程提前结束阻塞状态。
}
}

守护线程不是将原来线程改为守护线程,而是本来就是守护线程,别忘了setDaemon方法需要在start方法之前调用。
代码1:
public class Program { public static void main(String[] args) {
CounterThread counterThread = new CounterThread();
counterThread.setDaemon(true);
counterThread.start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} class CounterThread extends Thread { public void run() {
int i=1;
while(true){
System.out.println("计数器:"+i);
i++;
}
}
} 代码2:
import java.text.SimpleDateFormat;
import java.util.Date; /**
* 线程中所启动的其他非守护线程线程不会随着该线程的结束而结束
*/
public class ThreadDead { public static void main(String[] args) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
TimeThread timeThread = new TimeThread();
timeThread.start();//10秒后“任务管理器”中javaw.exe进程中线程数量会多一条
}
} class TimeThread extends Thread{ @Override
public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String currentTime = sdf.format(new Date());
System.out.println("时间线程,当前时间:"+currentTime);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
CounterThread counterThread = new CounterThread();
//counterThread.setDaemon(true);
counterThread.start();//10秒后“任务管理器”中javaw.exe进程中线程数量会再多一条
try {
Thread.sleep(5000);//一个时段后“任务管理器”中javaw.exe进程中线程数量会少一条,但计数器线程依然在工作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} class CounterThread extends Thread { public void run() {
int i=1;
while(true){
System.out.println("计数器线程:"+i);
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}


终止程序——无疾而终
class CounterThread extends Thread {
private boolean flag = true;
public void stopThread() {
flag = false;
}
public void run() {
int i = ;
while (flag) {
System.out.println("计数器线程:" + i);
i++;
try {
sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Program {
public static void main(String[] args) {
CounterThread counterThread = new CounterThread();
counterThread.start();
try {
Thread.sleep();// 15秒后线程终止
counterThread.stopThread();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
终止程序——暴毙死亡
class CounterThread extends Thread {
@Override
public void run() {
int i = ;
try {
while (true) {
System.out.println("计数器线程:" + i);
i++;
Thread.sleep();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Program {
public static void main(String[] args) {
CounterThread counterThread = new CounterThread();
counterThread.start();
try{
Thread.sleep();
}catch(InterruptedException e){
e.printStackTrace();
}
counterThread.interrupt();
}
}
上面CounterThread类不可这样写:
class CounterThread extends Thread {
@Override
public void run() {
int i=;
while(true){
System.out.println("计数器线程:"+i);
i++;
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
串行运行

代码1:
public class Test { private static Object shareData = new Object();//多线程间共享的数据 public static void main(String[] args) {
new CounterThread("线程1",shareData).start();
new CounterThread("线程2",shareData).start();
}
} class CounterThread extends Thread{ private Object shareData; public CounterThread(String threadName,Object shareData){
super(threadName);
this.shareData = shareData;
} @Override
public void run() {
synchronized (shareData) {
for (int i = ; i < ; i++) {
System.out.println(getName() + " : " + i);
}
}
}
} 代码2:
public class Test { public static void main(String[] args) {
new CounterThread("线程1").start();
new CounterThread("线程2").start();
}
} class CounterThread extends Thread { public CounterThread(String threadName) {
super(threadName);
} @Override
public void run() {
synchronized (CounterThread.class) {//执行代码3可知道为什么这样做也可以
for (int i = ; i < ; i++) {
System.out.println(getName() + " : " + i);
}
}
}
} 代码3:
public class Test { public static void main(String[] args){
System.out.println(Test.class == Test.class);
}
}
线程之间数据共享——并行运行
多个线程之间默认并发运行,这种运行方式往往会出现交叉的情况



线程之间数据共享——串行运行(synchronized)
使原本并发运行的多个线程实现串行运行,即多线程间同步执行,需要通过对象锁机制来实现,synchronized就是一个利用锁实现线程同步的关键字。



多线程同步原理
为什么通过synchronized就能实现多线程间串行运行呢?
被synchronized括着的部分就是线程执行临界区,每次仅能有一个线程执行该临界区中的代码:当多个线程中的某个线程先拿到对象锁, 则该线程执行临界区内的代码,其他线程只能在临界区外部等待,当此线程执行完临界区中的代码后,在临界区外部等待的其他线程开始再次竞争以获取对象锁,进而执行临界区中的代码,但只能有一条线程“胜利”。
临界区中的代码具有互斥性、唯一性和排它性:一个线程只有执行完临界区中的代码另一个线程才能执行。
package com.xt.two;
import java.text.*;
import java.util.Date; public class SynTest { public static void main(String[] args) {
Object lockObj = new Object();
new DisplayThread(lockObj).start();
}
} class DisplayThread extends Thread { Object lockObj; public DisplayThread(Object lockObj) {
this.lockObj = lockObj;
} @Override
public void run() {
synchronized (lockObj) {
new TimeThread(lockObj).start();
try {
sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class TimeThread extends Thread { Object lockObj; public TimeThread(Object lockObj) {
this.lockObj = lockObj;
} @Override
public void run() {
System.out.println("时间线程开始执行......");
synchronized (lockObj) {
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
String time = dateFormat.format(new Date());
System.out.println(time);
//为什么这行代码60秒左右才会执行?
//显示器线程和时间线程共享lockObj对象,显示器线程优先进入启动状态,随后执行相应的run方法,当执行同步代码块时lockObj变量所代表的对象锁归显示器线程所有,
//进而创建时间线程并使之处于启动状态,此时有一下两种状态:
//1、时间线程马上进入执行状态,
//马上执行该时间线程run方法,可是由于此时lockObj变量所代表的对象锁被显示器线程持有,
//这时时间线程进入阻塞状态,显示器线程再次执行,然后执行sleep方法,显示器线程在继续持有对象锁的前提下
//也进入阻塞状态,60秒后显示器线程进入执行状态,随后显示器线程结束,对象锁被释放,进而时间线程开始执行,进而这行代码运行;
//2、时间线程并没有马上进入执行状态,显示器线程执行sleep方法,显示器线程在继续持有对象锁的前提下
//也进入阻塞状态,此时时间线程进入执行状态,执行该时间线程run方法,执行该方法中第一行输出代码,
//可是由于此时lockObj变量所代表的对象锁被显示器线程持有,
//所以时间线程并没有执行时间线程run方法内临界区中的代码,这时时间线程也进入阻塞状态,此时显示器和时间两条线程均进去阻塞状态,
//等待少于60秒的时间后,显示器线程进入运行状态,随后显示器线程结束,对象锁被释放,进而时间线程开始执行,进而这行代码运行;
}
}
}
synchronized(this)
public class Test {
public static void main(String[] args) {
new CounterThread("线程1").start();
new CounterThread("线程2").start();
}
}
class CounterThread extends Thread{
public CounterThread(String threadName){
super(threadName);
}
@Override
public void run() {
synchronized (this) {//此时临界区中的代码无法实现串行执行,因为此时对象锁在线程1和线程2之间不共享
for (int i = 0; i < 3; i++) {
System.out.println(getName() + " : " + i);
}
}
}
}
public class Test {
public static void main(String[] args) {
new Thread(new CounterThread(),"线程1").start();
new Thread(new CounterThread(),"线程2").start();
}
}
class CounterThread implements Runnable {
@Override
public void run() {
synchronized (this) {// 此时临界区中的代码依然无法实现串行执行,因为每一个独立线程拥有一个独立的锁对象——new CounterThread()。
//要明白这两点:
//谁调用该run方法?——CounterThread类对象;
//谁执行该run方法?——正在执行的线程
Thread thread = Thread.currentThread();
for (int i = 0; i < 3; i++) {
System.out.println(thread.getName() + ":" + i);
}
}
}
}
public class Test {
public static void main(String[] args) {
Runnable counterThread = new CounterThread();
new Thread(counterThread,"线程1").start();
new Thread(counterThread,"线程2").start();
}
}
class CounterThread implements Runnable {
@Override
public void run() {
synchronized (this) {// 此时临界区中的代码可以实现串行执行,因为此时接口实现类对象充当了对象锁的功能,该对象锁在两个线程之间共享
Thread thread = Thread.currentThread();
for (int i = 0; i < 3; i++) {
System.out.println(thread.getName() + ":" + i);
}
}
}
}
线程死锁
如果有两个或两个以上的线程都访问了多个资源,而这些线程占用了一些资源的同时又在等待其它线程占用的资源,也就是说多个线程之间都持有了对方所需的资源,而又相互等待对方释放的资源,在这种情况下就会出现死锁。 多个线程互相等待对方释放对象锁,此时就会出现死锁
public class DeadLockThread {
// 创建两个线程之间竞争使用的对象
private static Object lock1 = new Object();
private static Object lock2 = new Object();
public static void main(String[] args) {
new ShareThread1().start();
new ShareThread2().start();
}
private static class ShareThread1 extends Thread {
public void run() {
synchronized (lock1) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("ShareThread1");
}
}
}
}
private static class ShareThread2 extends Thread {
public void run() {
synchronized (lock2) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("ShareThread2");
}
}
}
}
}
线程协作
import java.text.SimpleDateFormat;
import java.util.Date; public class ElectronicWatch { String currentTime; public static void main(String[] args) {
new ElectronicWatch().new DisplayThread().start();
} /**
* 该线程负责显示时间
*/
class DisplayThread extends Thread{ @Override
public void run() {
new TimeThread ().start();
System.out.println(currentTime);//为什么结果可能为null
}
} /**
* 该线程负责获取时间
*/
class TimeThread extends Thread{ @Override
public void run() {
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String pattern = "yyyy-MM-dd HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
currentTime = sdf.format(new Date());
}
}
}
代码2:
package test; import java.text.SimpleDateFormat;
import java.util.Date; public class ElectronicWatch { String currentTime; public static void main(String[] args) {
new ElectronicWatch().new DisplayThread().start();
} /**
* 该线程负责显示时间
*/
class DisplayThread extends Thread{ @Override
public void run() {
TimeThread timeThread = new TimeThread();
timeThread.start();
try {
sleep(5000);//这种方式不可取:这种方式性能不高
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(currentTime);
}
} /**
* 该线程负责获取时间
*/
class TimeThread extends Thread{ @Override
public void run() {
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String pattern = "yyyy-MM-dd HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
currentTime = sdf.format(new Date());
}
}
} 代码3:
package test; import java.text.SimpleDateFormat;
import java.util.Date; public class ElectronicWatch { String currentTime; public static void main(String[] args) {
new ElectronicWatch().new DisplayThread().start();
} /**
* 该线程负责显示时间
*/
class DisplayThread extends Thread{ @Override
public void run() {
TimeThread timeThread = new TimeThread();
timeThread.start();
try {
timeThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(currentTime);
}
} /**
* 该线程负责获取时间
*/
class TimeThread extends Thread{ @Override
public void run() {
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String pattern = "yyyy-MM-dd HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
currentTime = sdf.format(new Date());
}
}
}
代码4:wait和notify方法
package com.xt.two;
import java.text.SimpleDateFormat;
import java.util.Date; public class ElectronicWatch { String currentTime;
public static Object obj = new Object(); public static void main(String[] args) {
new ElectronicWatch().new DisplayThread(obj).start();
} /**
* 该线程负责显示时间
*/
class DisplayThread extends Thread{ Object obj; public DisplayThread(Object obj) {
this.obj = obj;
} @Override
public void run() {
TimeThread tt=new TimeThread (obj);
tt.start();
synchronized (obj) {
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(currentTime);//为什么结果可能为null
}
} /**
* 该线程负责获取时间
*/
class TimeThread extends Thread{ Object obj; public TimeThread(Object obj) {
this.obj = obj;
}
@Override
public void run() {
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String pattern = "yyyy-MM-dd HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
currentTime = sdf.format(new Date());
synchronized (obj) {
obj.notify();
}
}
}
}
java——多线程知识点大总结的更多相关文章
- java 多线程知识点
线程状态图 说明: 线程共包括以下5种状态. 新建状态(New) : 线程对象被创建后,就进入了新建状态.例如,Thread thread = new Thread(). 就绪状态(Runnable) ...
- Java多线程读取大文件
前言 今天是五一假期第一天,按理应该是快乐玩耍的日子,但是作为一个北漂到京师的开发人员,实在难想出去那玩耍.好玩的地方比较远,近处又感觉没意思.于是乎,闲着写篇文章,总结下昨天写的程序吧. 昨天下午朋 ...
- java多线程知识点
下面是我学习多线程记录的知识点,并没详细讲解每个知识点,只是将重要的知识点记录下来,有时间可以看看,如果有不对的地方,欢迎大家指出,谢谢! 1.多线程的状态和创建方式: 线程的状态: ...
- JAVA 多线程制作大球吃小球 一、实现球的自动生成及运动 生产消费模型
前几天用多线程实现了创建小球并移动,想到大鱼吃小鱼,便突发奇想要写一个大球吃小球.首先第一步自然是先把界面弄好啦 public class BallUI extends JPanel { privat ...
- java多线程知识点汇总(一)多线程基础
1.什么叫多线程程序? 答:一个进程至少有一个线程在运行,当一个进程中出现多个线程时,就称这个应用程序是多线程应用程序. java编写的程序都是多线程的,因为最少有俩线程,main主线程和gc线程. ...
- 软帝学院:java多线程知识点分享
1.进程和线程: 进程:正在进行的程序.每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元. 线程:进程内部的一条执行路径或者一个控制单元. 两者的区别: 一个进程至少有一个线程 ...
- java多线程知识点总结
1.线程调度知识:线程类Thread的了解,几个thread的方法.thread.sleep(),thread.join().(调用join方法的那个线程会立刻执行). object.wait()方法 ...
- java多线程知识点概述
这里只起一个概述的作用,极其简单的列一下知识点,需要在脑海中过一下,如果哪些方面不熟悉的话,建议利用网络资源去学习. 1.线程.进程概念 概念 线程状态及其转换 2.死锁.预防.解决 3.jdk线程实 ...
- java多线程知识点汇总(四)多线程知识点脉络图
1.多线程安全问题 1)synchronized关键字:如何加锁的问题,选择synchronized方法还是synchnized代码块. 选择哪个锁问题,this对象,还是class对象(针对stat ...
随机推荐
- 【零基础】搞定zabbix安装
一.前言 最近想做服务器压力测试,测试软件找到了,突然发现还没有很好的办法监控服务器运行情况,之前用过zabbix,所以想到说要不就用zabbix来监控服务器运情况,不过这次就要好好研究下zabbix ...
- 2018-2019-2 20165330《网络对抗技术》Exp10 Final 基于PowerShell的渗透实践
目录 实验内容 实验步骤 实验中遇到的问题 实验总结与体会 实验内容 PoweShell简介 PowerShell入门学习 PowerShell渗透工具介绍 相关渗透实践分析 ms15-034之Pow ...
- session cookie傻傻分不清
做了这么多年测试,还是分不清什么是cookie,什么是session?很正常,很多初级开发工程师可能到现在都搞不清什么是session,cookie相对来说会简单很多. 下面这篇文章希望能够帮助大家分 ...
- Vue入门下
使用npm创建项目,系统会自动生成一些列文件. 以慕课网上的Travel项目来说,在生成的项目文件中存在src文件夹,这个文件夹也是平时在做项目的时候用的比较多的,其他的一些配置信息更改的频率较低. ...
- TelephonyUtils
<uses-permission android:name="android.permission.CALL_PHONE"/> import java.util.Arr ...
- 语法错误 : 缺少“;”(在“<”的前面)
该错误有可能是由错误所指行“<”附近的某个类型忘记#include <>所造成的
- spark简单快速学习及打开UI界面---1
1.远程集群测试 import org.apache.spark.{SparkContext, SparkConf} import scala.math.random /** * 利用spark进行圆 ...
- MATLAB学习(一)数组、变量、表达式、常用简单运算
>> x=[1 2 3;4 5 6;7 8 9] x = 1 2 3 4 5 6 7 8 9 >> y=[1,2,3] y = 1 2 3 >> y=[1,2,3 ...
- kettle转换和任务的基本使用
0 创建转换 并保存0816_em.ktr 1 主对象树中选择DB连接,创建2个DB连接 2 创建表输入 核心对象树中选择输入>表输入 3 核心对象树中选择输出>插入/更新表 并连线 4 ...
- springcloud随便写点
eureka 注册注册 ribbon 负载均衡 feign 声名式client hystrix 断路器 zuul 网关,智能路由,过滤 config 集群配置 bus 分布式的节点用轻量的消息 ...