java线程的创建
文章目录
前言
本文章部分笔记来自自高诗岩的《java多线程编程核心技术》书。
进程
进程是操作系统结构的基础;是一次程序的执行;是一个程序及其数据在处理机上顺序执行时所发生的活动,是程序在一个数据及上运行的过程,它是系统进行资源分配和调度的一个独立单位。
线程
线程可以理解为在进程中独立运行的子任务,例如,QQ.exe运行时,很多的子任务也在同时运行,如好友视频线程、下载文件线程、传输数据线程、发送表情线程等,这些不同的任务或者说功能都可以同时运行,其中每一项任务完全可以理解成是“线程”在工作,传文件、听音乐、发送图片表情等这些功能都有对应的线程在后台默默地运行。
使用线程
继承Thread
public class MyTread extends Thread{
@Override
public void run(){
super.run();
System.out.println("MYThread");
}
}
public class Main {
public static void main(String[] args) {
MyTread mythreads = new MyTread();
mythreads.start();
System.out.println("结束");
}
}
线程随机性
线程的随机输出是因为CPU将时间片分给不同的线程,线程获得时间片后就执行任务,所以这些线程在交替地执行并输出导致输出结果呈现乱序的现象。
.start()的顺序不代表.run()的顺序
线程.start()的顺序并不代表.run()的顺序,和我们平常代码从上到下顺序执行不太一样。
实现Runnable
我们都知道java支持单继承,使用继承Thread类来开发多线程应用程序在设计上是有局限性的,所以在有些时候,我们可以继承一个类并用implement Runnable接口。
实例共享造成的非线程安全问题
当不共享时,多个线程都是访问各自的实例变量,对各自的变量进行操作, 不让多个线程访问同一个实例变量。
当共享数据时,即多个线程可以访问同一个实例变量。
public class Main {
public static void main(String[] args) {
MyTread mythreads = new MyTread();
Thread a = new Thread(mythreads,"A");
Thread b = new Thread(mythreads,"B");
Thread c = new Thread(mythreads,"C");
Thread d = new Thread(mythreads,"D");
Thread e = new Thread(mythreads,"E");
a.start();
b.start();
c.start();
d.start();
e.start();
}
}
public class MyTread extends Thread{
private int count =5;
@Override
public void run(){
super.run();
count--;
System.out.println("由"+ currentThread().getName()+"计算,count"+count);
}
}

我们预期希望时可以递减的,结果不应该重复,但是很明显,这样已经出现了所谓的非线程安全问题。
典型场景:5个销售员卖产品,在售出一个产品后,应该在剩余物品上进行减1操作,这个时候就需要对多个线程进行同步的操作。
我们可以在run方法前面加上一个synchronized关键字,这样线程在对这个订单数量减少时就需要排队进行了
线程常用方法:
currentThread() 方法,返回代码段正在被哪个线程调用。
isAlive() 方法,判断当前的线程是否存活。
sleep() 方法,在指定的时间内让当前"正在执行的线程"休眠(暂停执行)
getId()获取线程的唯一标识
判断线程是否为停止状态
1)public static boolean interrupted():测试currentThread()是否已经中断。
2)public boolean this.isInterrupted():测试this关键字所在类的对象是否已经中断。
interrupted():测试当前线程是否已经中断,线程的中断状态由该方法清除。
两个方法的区别:
1)this.interrupted():测试当前线程是否已经是中断状态,执行后具有清除状态标志值为false的功能。
2)this.isInterrupted():测试线程Thread对象是否已经是中断状态,不清除状态标志。
用stop()方法停止线程,即暴力停止线程
利用
stop()方法已经是作废的方法,因为如果暴力性地强制让线程停止,一些请理性工作得不到完成,或者数据添加不完整。
利用stop()释放锁给数据造成不一致的结果
暂停线程suspend()和resume()
使用suspend()方法可以暂停线程,使用resume()方法来恢复线程的执行。
两者的缺点:独占
当使用方法不当,极易造成公共同步对象被独占,其他线程就无法访问公共同步对象的结果。
当一个线程对一个对象的操作一直都没有结束,其他线程就不能访问这个对象,假如这个线程操作这个对象永远进入suspend()状态,其他线程就不能再访问这个对象了。
缺点二:数据不完整
在使用两个方法时容易出现线程暂停,进而导致数据不完整的情况。
yield方法
这个方法是放弃当前的CPU资源,让其他任务去占用CPU执行时间,放弃时间不确定,有可能刚刚放弃,马上又获得CPU时间片。
线程的优先级
线程可以划分优先级,优先级较高的线程得到CPU资源较多,也就是CPU优先执行优先级较高的线程对象中的任务,其实就是让高优先级的线程获得更多的CPU时间片。
通过setPriority()方法设置线程的优先级
在java中,线程的优先级一般分为1~10共10个等级。
线程优先级的继承特性
在Java中,线程的优先级具有继承性
A启动B,A和B的优先级是一样的
优先级的规律性
setPriority()方法设置线程的优先级
一般情况下,高优先级的线程总是大部分先执行完,但是不代表高优先级的线程全部先执行完。
优先级的随机性
优先级较高的线程不一定每一次都先执行完。即:优先级高的线程并不一定每一次都先执行完run()中的任务,线程优先级与输出顺序无关。
守护线程
Java中有两种线程:一种是用户线程,也称非守护线程;另一种是守护线程。
当线程中不存在非守护线程,守护线程自动销毁。典型的守护线程就是垃圾回收机制。当最后的一个用户线程销毁了,守护线程退出,进程随即结束了。
public class Run {
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.setDaemon(true);
thread.start();
Thread.sleep(10000);
System.out.println("我离开thread对象也不再打印了,也就是停止了!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class MyThread extends Thread {
private int i = 0;
@Override
public void run() {
try {
while (true) {
i++;
System.out.println("i=" + (i));
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
传入setDaemon(true)的线程即为守护线程,所以这里面我们可以看出main是属于用户线程,怎么样可以快速判断出来呢,比如我们将这一行代码注释掉,那么这里在main线程结束后,但是MyThread线程还没有结束,即用户线程还么有结束,这时守护线程就不会终止,所以注释掉后,运行起来这个线程就不会终止了。
对象及变量的并发访问
非线程安全问题会在多个线程对同一个对象中的实例变量进行并发访问时发生,产生的后果就是“脏读”,也就是读取到的数据其实是被更改过的。而线程安全是指获得实例变量的值是经过同步处理的,不会出现脏读的现象。
方法内的变量为线程安全
非线程安全问题存在于实例变量中,对于方法内的私有变量,不存在非线程安全问题
解决方案:
当两个线程同时访问同一个对象的同步方法一定是线程安全的。当线程进入synchronized声明的方法时就会上锁,得等这个方法执行完成后,下一个线程才会进入synchronized声明的方法中。
synchronized方法
调用用关键字synchronized声明的方法一定是排队进行运行的。另外,需要牢牢记住“共享”这两个字,只有共享资源的读写访问才需要同步化,如果不是共享资源,那么就没有同步的必要。
当一线程调用一个对象的synchronized类型方法时,其他线程可以调用该对象的的非synchronized方法。
当在一个方法添加synchronized并不是锁方法,而是锁当前的类的对象。在Java中,“锁”就是对象,“对象”可以映射成“锁”,哪个线程拿到这把锁,哪个线程就可以执行这个对象的synchronized同步方法。
synchronized拥有重入锁的功能,当一个线程得到一个对象的锁后,再次请求此对象锁时可
以得到该对象锁的,意思就是当我们在一个synchronized方法内调用其他方法块时,是可以得到锁的。
“可重入锁”是指自己还可以获取自己的内部锁。
synchronized方法和synchronized(this)代码块都是锁定当前对象。
总结
简单的一个学习笔记,记录一下。
java线程的创建的更多相关文章
- Java线程:创建与启动
Java线程:创建与启动 一.定义线程 1.扩展java.lang.Thread类. 此类中有个run()方法,应该注意其用法: public void run() 如果该线程是使用独立的 R ...
- 漫谈并发编程(二):java线程的创建与基本控制
java线程的创建 定义任务 在java中使用任务这个名词来表示一个线程控制流的代码段,用Runnable接口来标记一个任务,该接口的run方法为线程运行的代码段. public ...
- JAVA - 线程从创建到死亡的几种状态都有哪些?
JAVA - 线程从创建到死亡的几种状态都有哪些? 新建( new ):新创建了一个线程对象. 可运行( runnable ):线程对象创建后,其他线程(比如 main 线程)调用了该对象 的 sta ...
- Java线程之创建线程
翻译自:https://www.journaldev.com/1016/java-thread-example 进程 进程是一个自包含的执行环境,它可以被看成一个程序或应用程序.然而一个应用程序本身包 ...
- 【JAVA并发第二篇】Java线程的创建与运行,线程状态与常用方法
1.线程的创建与运行 (1).继承或直接使用Thread类 继承Thread类创建线程: /** * 主类 */ public class ThreadTest { public static voi ...
- Java线程的创建及启动
1.继承Thread类,重写该类的run()方法. package samTest; import java.util.Scanner; /** * Created by Sam on 2018-01 ...
- Java 线程的创建和启动
Java 使用 Thread 类代表线程,所有的线程对象都必须是 Thread 类或其子类的实例.每个线程的作用是完成一定的任务,实际上就是执行一段程序流(一段顺序执行的代码). Java 使用线程执 ...
- Java线程的创建方式三:Callable(四)
一.Java实现多线程的三种方式 方式一:继承Thread类: public class Test extends Thread { public static void main(String[] ...
- java线程之创建线程类
1.extends Thread方法 class Person extends Thread { int sum1 = 50; // 含参构造器 public Person(String name) ...
- ThreadPoolExecutor – Java Thread Pool Example(java线程池创建和使用)
Java thread pool manages the pool of worker threads, it contains a queue that keeps tasks waiting to ...
随机推荐
- python openpyxl 多个sheet vlookup
import pandas as pdimport openpyxlfrom openpyxl.styles import Border, Side,colorswb = openpyxl.load_ ...
- SpringSecurity登录验证,多个用户表
在开始之前我想感叹一句,技术久了不回头看看真的会忘记的,这次公司让我重新开发一个程序,项目架构为单体多模块开发,其中有个需求就是需要不同用户表进行登录,且不同表的用户名.手机号都可以重复. 这样的需求 ...
- ValueError: unsupported format character ‘Y‘ (0x59) at index 70
错误信息:ValueError: unsupported format character 'Y' (0x59) at index 70产生原因:因为python执行的sql中存在类似DATE_FOR ...
- typescript开发vue项目二次封装的axios用return Promise.reject(error) 返回异常,提示[Vue warn]: Error in v-on handler (Promise/async)
二次封装axios时刻意服务端模拟了延迟返回数据的场景,用return Promise.reject(error) 返回异常,报如下错误, [Vue warn]: Error in v-on hand ...
- VSCode 开发Vue + ElementUI
参考 (1)VSCode 开发Vue + ElementUI (2)玩转VSCode-完整构建VSCode开发调试环境 (shuzhiduo.com) (3)使用vscode搭建vue项目并引用ele ...
- c++实现类似python的map一样,批量操作一个vector的功能【python一样写c++、三】
python里有一个东西,叫map. 它可以实现像这样,对list每个元素进行操作,并返回新的list(python3是迭代器) 像这样 a=list(map(int,input().split()) ...
- superset连接mysql数据
目前superset的官网没给出windows的安装教程,但是实际操作是可以的,网上有很多教程,再次就不赘述! 本篇随笔是介绍superset如何连接mysql数据源,本人踩坑踩了一整天.=_= ~~ ...
- 利用Intent在两个页面之间进行传值操作的具体实现
不知道为什么,我本来使用的呼声最高的Bundle发送,但是我使用它会显示不出来,由于时间问题,我今天就先不找了,先放一下,先以完成任务为己任哈! 我们都清楚,我们基本上都是用的Intent实现的页面之 ...
- Debiased Contrastive Learning of Unsupervised Sentence Representations 论文精读
1. 介绍(Introduction) 问题: 由PLM编码得到的句子表示在方向上分布不均匀, 在向量空间中占据一个狭窄的锥形区域, 这在很大程度上限制了它们的表达能力. 已有的解决办法: 对比学习. ...
- c#动态执行字符串脚本(优化版)
像javascript中有eval()来执行动态代码,c#中是没有的,于是自己动手丰衣足食, 先来代码 1 using System; 2 using System.Data; 3 using Sys ...