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 ...
随机推荐
- SQLyog中创建的数据库在idea找不到
在里面把需要的数据库
- WinForm中的MVC模式--MVP模式
本文主要介绍MVC模式在WINFORM中的实现,其实砖家们都称它为MVP模式,小弟E文不太好,真的是记不住那个P怎么拼写的.. MVC模式主要解决的问题就是将表示层和业务层进行分离,在以往做WINFO ...
- vs2019远程调试win7系统的程序
vs2019远程调试 一.安装vs2019远程调试工具 首先让调试的电脑(也就是不安装vs2019的电脑),安装vs2019远程调试工具:VS_RemoteTools.exe. 网址:进行下载.h ...
- Python第四章实验报告
一.实验项目名称:<零基础学Python>第四章的14道实例和4道实战 二.实验环境:IDLE(Python 3.9 64-bit) 三.实验目的和要求:熟练掌握Python序列的应用 四 ...
- Python中的join函数用法
函数:string.join()Python中有join()和os.path.join()两个函数,具体作用如下: join(): 连接字符串数组.将字符串.元组.列表中的元素以指定的字符 ...
- Xamarin.Android 利用作业计划程序实现ImageSwitcher图片自动定时轮播
在开发android程序时,遇到一个问题,ImageSwitcher只支持手动的切换图片,不支持自动定时的切换.因为xamarin的资料很少,官方也没有相应的教程,所以想到这个方法,利用job程序来实 ...
- Python基础教程:字典
字典 = {'键1':'值1','键2':'值2','键3':'值3',...} animal_dict = {'Cow':'Milk','Chicken':'egg'} 字典由键值对构成,这种键值对 ...
- SpringBoot——拦截器
更多内容,前往 IT-BLOG 一.登录时可能会出现重复提交问题.我们可以通过重定向解决此问题.例如:用户提交的请求为:/user/login,通过 redirect:重定向至 main.html请求 ...
- 【LeetCode动态规划#05】背包问题的理论分析(基于代码随想录的个人理解,多图)
背包问题 问题描述 背包问题是一系列问题的统称,具体包括:01背包.完全背包.多重背包.分组背包等(仅需掌握前两种,后面的为竞赛级题目) 下面来研究01背包 实际上即使是最经典的01背包,也不会直接出 ...
- Clion 连接 WSL 编译Unix环境
Clion 连接 WSL 编译Unix环境 安装 WSL Ubuntu 18版本,创建后不要换源,upgrade后安装CMake.g++.gcc 安装 Clion,创建项目 进入setting 在 B ...