前言

本文章部分笔记来自自高诗岩的《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线程的创建的更多相关文章

  1. Java线程:创建与启动

    Java线程:创建与启动 一.定义线程   1.扩展java.lang.Thread类.   此类中有个run()方法,应该注意其用法: public void run() 如果该线程是使用独立的 R ...

  2. 漫谈并发编程(二):java线程的创建与基本控制

    java线程的创建 定义任务           在java中使用任务这个名词来表示一个线程控制流的代码段,用Runnable接口来标记一个任务,该接口的run方法为线程运行的代码段. public ...

  3. JAVA - 线程从创建到死亡的几种状态都有哪些?

    JAVA - 线程从创建到死亡的几种状态都有哪些? 新建( new ):新创建了一个线程对象. 可运行( runnable ):线程对象创建后,其他线程(比如 main 线程)调用了该对象 的 sta ...

  4. Java线程之创建线程

    翻译自:https://www.journaldev.com/1016/java-thread-example 进程 进程是一个自包含的执行环境,它可以被看成一个程序或应用程序.然而一个应用程序本身包 ...

  5. 【JAVA并发第二篇】Java线程的创建与运行,线程状态与常用方法

    1.线程的创建与运行 (1).继承或直接使用Thread类 继承Thread类创建线程: /** * 主类 */ public class ThreadTest { public static voi ...

  6. Java线程的创建及启动

    1.继承Thread类,重写该类的run()方法. package samTest; import java.util.Scanner; /** * Created by Sam on 2018-01 ...

  7. Java 线程的创建和启动

    Java 使用 Thread 类代表线程,所有的线程对象都必须是 Thread 类或其子类的实例.每个线程的作用是完成一定的任务,实际上就是执行一段程序流(一段顺序执行的代码). Java 使用线程执 ...

  8. Java线程的创建方式三:Callable(四)

    一.Java实现多线程的三种方式 方式一:继承Thread类: public class Test extends Thread { public static void main(String[] ...

  9. java线程之创建线程类

    1.extends Thread方法 class Person extends Thread { int sum1 = 50; // 含参构造器 public Person(String name) ...

  10. ThreadPoolExecutor – Java Thread Pool Example(java线程池创建和使用)

    Java thread pool manages the pool of worker threads, it contains a queue that keeps tasks waiting to ...

随机推荐

  1. 会长哥哥帮助安装ubuntu

    今晚突然想到要安装虚拟机,因为我原来上的python预科班里面讲解安装虚拟机,但是我当时没有安装上,导致预科班后面的课我没听懂,今天听课讲到字符和编码 所以想到了我的虚拟机,于是今晚很谨慎的求助会长大 ...

  2. MSVC设置版本

    MSVC设置版本 在开发QT时,由于QT 5.12与MSVC 2017兼容,因此需要用MSVC 2017来编译使用QT 5.12的程序. 1 安装MSVC 2017 由于笔者电脑上安装的Visual ...

  3. [UnityAI]行为树的中断机制

    参考链接: https://www.cnblogs.com/01zxs/p/9863715.html https://blog.csdn.net/AcmHonor/article/details/12 ...

  4. 修改百分浏览器(centbrowser)、谷歌和火狐浏览器默认字体的方法

    1,百分浏览器(centbrowser) 在浏览器的安装位置D:\Program Files\Cent Browser\User Data编辑文件custome.css,如果没有此文件可新建一个,内容 ...

  5. ffmpeg gcc is unable to create an executable file C compiler test failed

    ffmpeg 编译出现 #sudo ./configure --enable-shared --prefix=/usr/local/ffmpeg gcc is unable to create an ...

  6. 人脸关键点的应用场景及重难点解析丨Dev for Dev 专栏

    本文为「Dev for Dev 专栏」系列内容,作者为声网视频组 AI 算法工程师 周世付. 人脸检测.人脸关键点检测,是计算机视觉的基础算法.许多酷炫应用背后,例如美颜.贴纸.人脸驱动 avatar ...

  7. University of Toronto Faculty of Arts and Science MAT344– Final Assessment Combinatorics Instructors: Stanislav Balchev and Max Klambauer 19 August 2020

    目录 随便找的一份测试题 T7 T9 T6 T5 solution to (a) solution to (b) solution to (c) solution to (d) T1 T2 T3 T4 ...

  8. 快速傅里叶变换应用(FFT Applications)

    1. 3-SUM 1.1 问题描述 Given three sets \(X\), \(Y\), and $Z $ of \(n\) integers each, determine whether ...

  9. 利用 Rainbond 云原生平台简化 Kubernetes 业务问题排查

    Kubernetes 已经成为了云原生时代基础设施的事实标准,越来越多的应用系统在 Kubernetes 环境中运行.Kubernetes 已经依靠其强大的自动化运维能力解决了业务系统的大多数运行维护 ...

  10. Redis事件机制(未写完)

    Redis服务器是一个事件驱动程序,服务器需要处理以下两类事件: 文件事件:Redis通过套接字与客户端连接,文件事件是服务器对套接字操作的抽象. 时间事件:Redis服务器中的一些操作需要给定的时间 ...