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 ...
随机推荐
- Linux设备驱动程序 之 顺序锁
当要保护的资源很小,很简单,会频繁的被访问而且写入访问很少的且必须快速时(即读不允许让写饥饿),就可以使用顺序锁(seqlock):从本质上讲,顺序锁会允许读取者对资源的自由访问,但需要读取者检查是否 ...
- python格式化输出(% format用法)
%基本用法: 十进制输出:print('%d' % 6) 6也可以换成其它的数字变量 八进制输出:print('%o' % 6) 6也可以换成其它的数字变量 字符串输出:print('%s' ...
- centOS7搭建hadoop,zookeeper,hbase
1.配置ssh免密登录 (本人使用的是centOS7虚拟机) (本人未在root用户下安装,建议使用root用户,不然很麻烦!!) ① 本机无密钥登录 1.进入~/.ssh目录(若无,则执行一次ssh ...
- LeetCode 简化路径(探索字节跳动)
题目描述 给定一个文档 (Unix-style) 的完全路径,请进行路径简化. 例如, path = "/home/", => "/home" path ...
- Linux | linux的那些常见目录
1. bin目录 binary(二进制的):许多"指令"对应的可"执行程序文件"目录 2. sbin目录 说明:super binary 超级的 二进制 许多& ...
- mybatis之动态SQL操作之删除
/** * 持久层 */ public class StudentDao { /** * 动态SQL--删除 */ public void dynaSQLwithDelete(int... ids) ...
- 模型压缩-Learning Efficient Convolutional Networks through Network Slimming
Zhuang Liu主页:https://liuzhuang13.github.io/ Learning Efficient Convolutional Networks through Networ ...
- python-Web-数据库-oracle
1.oracle体系结构 --------全局数据库,这里指物理磁盘上的数据库(物理结构,一个真实存在的磁盘目录),一般一台oracle服务器有1个全局数据库,文件占1G多.oracle允许一台 -- ...
- 一些常见的MySQL配置
目录 配置 参考 配置 [mysqld] port = 3306 socket = /mysql/log/mysql_3306.sock # mysql的目录(即mysql的文件所在目录) # bas ...
- DP————LIS(最长上升子序列)和LCS(最长公共子序列)问题
LIS问题 https://www.acwing.com/problem/content/898/ 思路:首先数组a中存输入的数(原本的数),开辟一个数组f用来存结果,最终数组f的长度就是最终的答案: ...