前言

进程是计算机中程序关于某几何数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。是操作系统结构的基础

线程可以说是轻量级的进程,是程序执行的最小单位,使用多线程而不用多进程去进行并发程序的设计,是因为线程之间的切换与调度的成本远小于进程。

线程的几种状态

New状态表示刚刚创建的线程,这种线程还没有开始执行
RUNNABLE:当线程创建好之后,调用线程的start方法就会进入就绪状态。
BLOCKED:当线程运行过程如果遇到了Syschronized就会进入阻塞状态。
TIMED_WATING:表示等待状态,有时间限制的(sleep)
WAITING:表示进入一个无时间显示的等待状态(wait)
TERMINATED:表示结束状态。

线程的基本操作

新建线程

实现Runable接口或者new Thread

终止线程

为什么不建议使用stop?

因为stop方法比较暴力,强行把执行的程序终止,可能会引发数据不一致的问题,Thread.stop()方法在结束线程时,会直接终止线程,并立即释放这个线程的所持有的锁。比如数据写到一半,强行终止掉了,数据就会被破坏。

线程中断

interrupt() //中断线程。相当于设置中断标志位
isInterrypted() //判断是否被中断
interrupted() //判断是都被中断,并清除当前的中断状态

Thread.sleep()方法由于中断而抛出异常,此时它会清除中断标记,如果不加处理,那么下一次循环开始时,就无法捕获这个异常,可以再次设置中断标记来方便循环判断。

等待和通知

当在一个对象实力上条用wait()方法之后。当前线程就会在这个对象上等待。在线程A中调用了obj.wait()方法,那么变成A就会停止继续执行,转为等待状态,直到其他线程调用了obj.notify()方法才有机会继续执行(并不是一定)

如果一个线程调用了obj.wait()那么它就会进入这个object的等待队列,这个等待队列可能会有多个线程,因为系统运行多个线程同时等待某一个对象,当obj.notify()方法被调用时,就会随机选择一个线程,将其唤醒,这个唤醒是完全随机的。

notifyAll()方法的功能是唤醒所有在该对象等待队列中等待的线程。

守护线程的finally不一定会执行。如果除守护线程外的所有线程都结束了,那么守护线程就立即退出没有执行finally代码块的机会。

挂起(suspend)和继续(resume)执行

不推荐执行suspend(),因为该方法在导致线程暂停的同时,并不会释放任何资源。影响其他想要访问该资源的线程,直到当前线程使用resume操作,是当前线程继续执行,但是此处有一个隐患。如果resume在suspend之前运行了,那么被挂起的线程将不能继续执行下去。

public class BadSuspend {
public static Object u = new Object();
static ChangeObjectThread t1 = new ChangeObjectThread("t1");
static ChangeObjectThread t2 = new ChangeObjectThread("t2"); public static class ChangeObjectThread extends Thread {
public ChangeObjectThread(String name){
super.setName(name);
}
@Override
public void run() {
synchronized (u) {
System.out.println("in "+getName());
Thread.currentThread().suspend();
}
}
} public static void main(String[] args) throws InterruptedException {
t1.start();
Thread.sleep(100);
t2.start();
t1.resume();
t2.resume();//无法直到这一行先执行,还是Thread.currentThread().suspend();先执行
t1.join();
t2.join();
}
}

等待线程结束(join)和谦让(yeild)

public final synchronized void join(long millis) throws InterruptedException//有最大等待时长的等待

public final synchronized void join(long millis, int nanos)
throws InterruptedException//毫秒,加纳秒级别的等待 public final void join() throws InterruptedException//表示无限期的等待
package com.atmb.me;

public class joinAndYeild {
public volatile static int i =0; public static class myThread implements Runnable{
@Override
public void run() {
for (int j = 0; j < 1000000; j++) {
i+=1;
}
}
} public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new myThread());
thread.start();
thread.join();//等待thread线程执行结束
System.out.println(i);//结果为1000000
}
}
    public static native void yield();

这个方法一旦执行,就会使当前线程让出cpu,让出cpu之后,该线程会继续进行cpu资源的争夺,之后继续正常运行。

线程组

package com.atmb.me;

public class ThreadGroupTest implements Runnable {

    @Override
public void run() {
System.out.println(Thread.currentThread().getThreadGroup().getName()+"==="+Thread.currentThread().getName());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
ThreadGroup group1 = new ThreadGroup("group1");
Thread thread1 = new Thread(group1, new ThreadGroupTest());
Thread thread2 = new Thread(group1, new ThreadGroupTest());
thread1.start();
thread2.start();
System.out.println(group1.activeCount());//活跃线程数
group1.list();
}
}
<<<
2
group1===Thread-0
java.lang.ThreadGroup[name=group1,maxpri=10]
group1===Thread-1
Thread[Thread-0,5,group1]
Thread[Thread-1,5,group1]

守护线程(Daemon)

守护线程要守护的对象已经不存在了,那么整个应用程序就应该技术,因此当java应用内只有守护线程时,java虚拟机就会自然退出。

package geym.ch2;

public class DaemonDemo {
public static class DaemonT extends Thread{
public void run(){
while(true){
System.out.println("I am alive");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t=new DaemonT();
t.setDaemon(true);
t.start(); // Thread.sleep(2000);
}
}

设置守护线程,必须要在start之前设置,否则会得到异常信息。

线程优先级

Java中的线程可以有自己的优先级。优先级高的线程在竞争资源时,会更有优势,更大概率抢占到资源,java中线程优先级可以设置为1-10.

其中有三个静态标量标识三个对应的优先级。

    /**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1; /**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5; /**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
public class PriorityDemo {
public static class HightPriority extends Thread{
static int count=0;
public void run(){
while(true){
synchronized(PriorityDemo.class){
count++;
if(count>10000000){
System.out.println("HightPriority is complete");
break;
}
}
}
}
}
public static class LowPriority extends Thread{
static int count=0;
public void run(){
while(true){
synchronized(PriorityDemo.class){
count++;
if(count>10000000){
System.out.println("LowPriority is complete");
break;
}
}
}
}
} public static void main(String[] args) throws InterruptedException {
Thread high=new HightPriority();
LowPriority low=new LowPriority();
high.setPriority(Thread.MIN_PRIORITY);
low.setPriority(Thread.MAX_PRIORITY);
low.start();
high.start();
}
}

线程安全与关键字synchronized

synchronized

  • 指定加锁对象,对给定的对象进行加锁,
  • 用于实例方法,对当前的实例进行加锁
  • 用于静态方法,对当前类进行加锁

错误的加锁

package com.atmb.me;

public class lockError implements Runnable {
public static Integer i =0;
public static lockError instance = new lockError(); public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(instance);
Thread thread2 = new Thread(instance);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(i);
} @Override
public void run() {
for (int j = 0; j < 100000; j++) {
synchronized (i){
i+=1;
}
}
}
}
<<<
142957

原因在于Integer类型属于不可变对象,一旦创建就不可能被改变,当integer对象赋值为新值时,当前引用指向的对象就改变了。

指令重排的前提

指令重排需要保证串行语义的一致性,指令重排不会使串行的语义逻辑发生问题。

指令重排的目的?

为了减少中断流水线

那些指令不能重排

  • 程序顺序原则,一个线程内保证语义的串行性
  • volatile规则:volatile变量的写先与读发生,宝整理volatile变量的可见性
  • 传递性:解锁必然发生在随后的加锁前
  • 线程的start()方法先于它的动作
  • 线程的所有操作先于线程的终结(interrupt)
  • 线程的中断(interrupt())先于被中断线程的代码
  • 对象的构造函数的执行,结束先于finalize()的方法

是否会释放锁

  • yield让出cpu执行权,不会释放锁

  • sleep休眠时,不会释放锁

  • 调用wait方法之后,会释放锁,唤醒之后,会再次竞争锁,然后执行wait()方法后的代码

  • nofify nodifyall 对锁没有影响,一般放同步代码块的最后一行

最后

感谢你看到这里,看完有什么的不懂的可以在评论区问我,觉得文章对你有帮助的话记得给我点个赞,每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!

还不懂Java高并发的,建议看看这篇阿里大佬的总结,写的非常详细的更多相关文章

  1. java高并发系列【共34篇,强力建议观看】

    第1天:必须知道的几个概念 第2天:并发级别 第3天:有关并行的两个重要定律 第4天:JMM相关的一些概念 第5天:深入理解进程和线程 第6天:线程的基本操作 第7天:volatile与Java内存模 ...

  2. Java高并发与多线程(二)-----线程的实现方式

    今天,我们开始Java高并发与多线程的第二篇,线程的实现方式. 通常来讲,线程有三种基础实现方式,一种是继承Thread类,一种是实现Runnable接口,还有一种是实现Callable接口,当然,如 ...

  3. Java高并发秒杀API之Service层

    Java高并发秒杀API之Service层 第1章 秒杀业务接口设计与实现 1.1service层开发之前的说明 开始Service层的编码之前,我们首先需要进行Dao层编码之后的思考:在Dao层我们 ...

  4. 转载:Java高并发,如何解决,什么方式解决

    原文:https://www.cnblogs.com/lr393993507/p/5909804.html 对于我们开发的网站,如果网站的访问量非常大的话,那么我们就需要考虑相关的并发访问问题了.而并 ...

  5. java高并发系列 - 第6天:线程的基本操作

    新建线程 新建线程很简单.只需要使用new关键字创建一个线程对象,然后调用它的start()启动线程即可. Thread thread1 = new Thread1(); t1.start(); 那么 ...

  6. java高并发系列 - 第12天JUC:ReentrantLock重入锁

    java高并发系列 - 第12天JUC:ReentrantLock重入锁 本篇文章开始将juc中常用的一些类,估计会有十来篇. synchronized的局限性 synchronized是java内置 ...

  7. 跟着阿里p7一起学java高并发 - 第18天:玩转java线程池,这一篇就够了

    java中的线程池,这一篇就够了 java高并发系列第18篇文章. 本文主要内容 什么是线程池 线程池实现原理 线程池中常见的各种队列 自定义线程创建的工厂 常见的饱和策略 自定义饱和策略 线程池中两 ...

  8. 跟着阿里p7一起学java高并发 - 第19天:JUC中的Executor框架详解1,全面掌握java并发核心技术

    这是java高并发系列第19篇文章. 本文主要内容 介绍Executor框架相关内容 介绍Executor 介绍ExecutorService 介绍线程池ThreadPoolExecutor及案例 介 ...

  9. java高并发系列 - 第25天:掌握JUC中的阻塞队列

    这是java高并发系列第25篇文章. 环境:jdk1.8. 本文内容 掌握Queue.BlockingQueue接口中常用的方法 介绍6中阻塞队列,及相关场景示例 重点掌握4种常用的阻塞队列 Queu ...

随机推荐

  1. Microsoft.Extensions.DependencyInjection中的Transient依赖注入关系,使用不当会造成内存泄漏

    Microsoft.Extensions.DependencyInjection中(下面简称DI)的Transient依赖注入关系,表示每次DI获取一个全新的注入对象.但是使用Transient依赖注 ...

  2. dubbo配置的覆盖关系

    dubbo推荐在Provider上尽量多配置Consumer端属性: 由服务提供方设置超时,因为一个方法需要执行多长时间,服务提供方更清楚,如果一个消费方同时引用多个服务,就不需要关心每个服务的参数设 ...

  3. day03 爬虫基础

    一.爬虫原理1.互联网:由一堆网络设备把一台台计算机互联到一起称之为互联网2.互联网建立的目的:传递与共享数据3.上网的全过程普通用户: 打开浏览器---->往目标站点发送请求---->获 ...

  4. java前后端开发需掌握的框架及技术

    一.Java开发 1.J2EE架构及主流框架,spring4.spring boot.spring MVC.spring Security.spring cloud.struct2.hibernate ...

  5. 【译】值得推荐的十大React Hook 库

    十大React Hook库 原文地址:https://dev.to/bornfightcompany/top-10-react-hook-libraries-4065 原文作者:Juraj Pavlo ...

  6. 什么是SOAP?SOAP有什么用?什么时候会用到SOAP?

    什么是SOAP SOAP(Simple Object Access Protocol)一般指简单对象访问协议,简单对象访问协议是交换数据的一种协议规范,是一种轻量的.简单的.基于XML(标准通用标记语 ...

  7. Dev中配置graphcis.h

    下载地址:http://winbgim.codecutter.org/ 搞得自己有点奔溃 没成功 尝试了全网的所以的方法都没成功

  8. Mybatis初学经验----------------(2)

    至于myBatis的配置,上篇文章中有,就不说了.今天谈谈myBatis编写Dao层时的用法. 传统Dao层代码需求 1.在Dao层实现类中,存在大量的模板方法,能否提取模板方法,减少我们的工作量. ...

  9. 云计算管理平台之OpenStack启动虚拟机实例

    在前边的博客中,我们主要聊了下openstack的基础环境.核心服务(认证服务keystone/镜像服务glance/计算服务nova/网络服务neutron)的安装配置:回顾请查看前边的博客:今天我 ...

  10. Django项目-个人网站之投票模块

    Django项目之个人网站 关注公众号"轻松学编程"了解更多. Github地址:https://github.com/liangdongchang/MyWeb.git 感兴趣的可 ...