【系统学习】Java基础1之多线程

news/2024/12/28 20:01:51/

前言

被公司换岗一年多了,从Linux C换到了java开发,奈何大环境不好,半吊子经验找不到好工作。 接触了spring cloud, spring boot k8s等许多新的知识。已经开发Java生态相关项目已一年半,但都止步于用的阶段,自知毫无竞争力。故而系统学习一下Java,虽然知道很卷,但是也没办法了。

多线程

Thread类

  • 每个线程都是通过某个特定Thread对象的run()方法来完成操作的,经常把run()方法的主体称为线程体
  • 通过该Thread对象的start()方法来启动这个线程,而非直接调用run()

Thread 构造类

  • Thread() : 创建新的Thread对象

  • Thread(String threadname)创建线程并指定线程实例名

  • Thread(Runnable target): 指定创建线程的目标对象,它实现了Runnable接口中的Run方法

  • Thread(Runnable target, String name):创建新的Thread对象

public class ThreadDemo {public static void main(String[] args) {
//        MyThread1 m1 = new MyThread1();
//        MyThread2 m2 = new MyThread2();
//
//        m1.start();
//        m2.start();//创建Thread类的匿名子类的方式new Thread(){@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i % 2 == 0){System.out.println(Thread.currentThread().getName() + ":" + i);}}}}.start();new Thread(){@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i % 2 != 0){System.out.println(Thread.currentThread().getName() + ":" + i);}}}}.start();}
}class MyThread1 extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i % 2 == 0){System.out.println(Thread.currentThread().getName() + ":" + i);}}}
}class MyThread2 extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i % 2 != 0){System.out.println(Thread.currentThread().getName() + ":" + i);}}}
}

线程分类

Java中的线程分为两类:一种是守护线程,一种是用户线程

  • 它们在几乎每个方面都是相同的,唯一的区别是判断JVM何时离开
  • 守护线程是用来服务用户线程的,通过在start()方法前调用thread.setDaemon(true)可以把一个用户线程变成一个守护线程
  • Java垃圾回收就是一个典型的守护线程
  • 若JVM中都是守护线程,当前JVM将退出

生命周期

在这里插入图片描述

线程同步

Java对于多线程的安全问题提供了专业的解决方式:同步机制

  • 同步代码块
synchronized (对象){
// 需要被同步的代码;
}
  • 同步方法
public synchronized void show (String name){ 
….
}

同步机制中的锁

在《Thinking in Java》中,是这么说的:对于并发工作,你需要某种方式来防止两个任务访问相同的资源(其实就是共享资源竞争)。 防止这种冲突的方法

就是当资源被一个任务使用时,在其上加锁。第一个访问某项资源的任务必须锁定这项资源,使其他任务在其被解锁之前,就无法访问它了,而在其被解锁

之时,另一个任务就可以锁定并使用它了.

synchronized的锁是什么?

  • 任意对象都可以作为同步锁。所有对象都自动含有单一的锁(监视器)
  • 同步方法的锁:静态方法(类名.class)、非静态方法(this)
  • 同步代码块:自己指定,很多时候也是指定为this或类名.class

注意

  • 必须确保使用同一个资源的多个线程共用一把锁,这个非常重要,否则就无法保证共享资源的安全
  • 一个线程类中的所有静态方法共用同一把锁(类名.class),所有非静态方法共用同一把锁(this),同步代码块(指定需谨慎)

同步范围

代码是否存在线程安全

  • 明确哪些代码是多线程运行的代码
  • 明确多个线程是否有共享数据
  • 明确多线程运行代码中是否有多条语句操作共享数据

如何解决

对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。即所有操作共享数据的这些语句都要放在同步范围中

释放锁

  • 当前线程的同步方法、同步代码块执行结束
  • 当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行。
  • 当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束。
  • 当前线程在同步代码块、同步方法中执行了线程对象的**wait()**方法,当前线程暂停,并释放锁

不会释放锁的操作

  • 线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行
  • 线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁(同步监视器)。(应尽量避免使用suspend()和resume()来控制线程)

单例模式——懒汉(线程安全)

class Singleton {private static Singleton instance = null;private Singleton(){}public static Singleton getInstance(){if(instance==null){synchronized(Singleton.class){if(instance == null){instance=new Singleton();} } }return instance;} 
}
public class SingletonTest{public static void main(String[] args){Singleton s1=Singleton.getInstance();Singleton s2=Singleton.getInstance();System.out.println(s1==s2);} 
}

Lock锁

  • 从JDK 5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当

  • ava.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。

  • ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以

    显式加锁、释放锁。

class A{private final ReentrantLock lock = new ReenTrantLock();public void m(){lock.lock();try{//保证线程安全的代码;}finally{lock.unlock(); }}
}

注意:如果同步代码有异常,要将unlock()写入finally语句块

使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)

优先使用顺序

Lock ->同步代码块(已经进入了方法体,分配了相应资源) -> 同步方法(在方法体之外)

package com.atguigu.java1;import java.util.concurrent.locks.ReentrantLock;/*** 解决线程安全问题的方式三:Lock锁  --- JDK5.0新增** 1. 面试题:synchronized 与 Lock的异同?*   相同:二者都可以解决线程安全问题*   不同:synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器*        Lock需要手动的启动同步(lock()),同时结束同步也需要手动的实现(unlock())** 2.优先使用顺序:* Lock  同步代码块(已经进入了方法体,分配了相应资源)  同步方法(在方法体之外)*/
class Window implements Runnable{private int ticket = 100;//1.实例化ReentrantLockprivate ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while(true){try{//2.调用锁定方法lock()lock.lock();if(ticket > 0){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":售票,票号为:" + ticket);ticket--;}else{break;}}finally {//3.调用解锁方法:unlock()lock.unlock();}}}
}public class LockTest {public static void main(String[] args) {Window w = new Window();Thread t1 = new Thread(w);Thread t2 = new Thread(w);Thread t3 = new Thread(w);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}

Callable接口

与使用Runnable相比, Callable功能更强大些

  • 相比run()方法,可以有返回值
  • 方法可以抛出异常
  • 支持泛型的返回值
  • 需要借助FutureTask类,比如获取返回结果

Future接口

  • 可以对具体Runnable、Callable任务的执行结果进行取消、查询是否完成、获取结果等
  • FutrueTask是Futrue接口的唯一的实现类
  • FutureTask 同时实现了Runnable, Future接口。它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值

http://www.ppmy.cn/news/105610.html

相关文章

【数据挖掘与商务智能决策】第十六章 关联分析算法

16.1.3 Apriori算法的代码实现 1.apyori库代码实现关联规则 # apyori库的安装&#xff1a;将下面代码注释取消后运行 # !pip install apyoritransactions [[A, B, C], [A, B], [B, C], [A, B, C, D], [B, C, D]]from apyori import apriori rules apriori(transactions, mi…

delmia机器人建模与装配

1 可以用catia中的模型或其他三维建模软件中的模型转化为step格式即可 2 在demlia中打开 3 打开单个零件保存为cgr格式 对机械臂所有零件都做同样的转化 4 新建装配设计&#xff0c;并导入带有坐标的零件 将转化后的零件都选中导入即是装配好的 5 将模式修改为device buildin…

华三杯H3C 网络知识学习笔记(1)

通俗易懂的IP地址、子网掩码、默认网关、DNS服务器 https://blog.csdn.net/belongtocode/article/details/106453395 一文搞懂网络知识&#xff0c;IP、子网掩码、网关、DNS、端口号 https://zhuanlan.zhihu.com/p/65226634 图解 | 原来这就是网络 https://www.cnblogs.com/f…

华为OD机试真题B卷 Java 实现【求小球落地5次后所经历的路程和第5次反弹的高度】,附详细解题思路

一、题目描述 假设一个球从任意高度自由落下&#xff0c;每次落地后反跳回原高度的一半; 再落下, 求它在第5次落地时&#xff0c;共经历多少米?第5次反弹多高&#xff1f; 数据范围&#xff1a;输入的小球初始高度满足 1 \le n \le 1000 \1≤n≤1000 &#xff0c;且保证是一…

面试高频—TCP/IP十大问题—程序员必备基础素养

目录 导读 TCP/IP十个问题 一、TCP/IP模型 二、数据链路层 三、网络层 四、ping 五、Traceroute 六、TCP/UDP 七、DNS 八、TCP连接的建立与终止 九、TCP流量控制 十、TCP拥塞控制 &#x1f4da; 相关参考资料 导读 本文整理了一些TCP/IP协议簇中需要必知必会的十…

为什么现在定制开发APP的时间越来越长?

最近几年&#xff0c; APP开发的时间越来越长&#xff0c;让很多企业都难以接受。对于不少企业来说&#xff0c;他们需要花很长时间才能完成 APP定制开发&#xff0c;不仅耗费了大量的时间和精力&#xff0c;而且开发出来的产品还不一定能达到他们想要的效果。这让他们很头疼。…

Python3数据分析与挖掘建模(5)数据分类与分析

1. 数据分类 数据分类可以根据不同的度量水平进行分类&#xff0c;其中常见的分类方法包括定类、定序、定距和定比。 &#xff08;1&#xff09;定类&#xff08;Nominal&#xff09;&#xff1a;定类是最基本的数据分类方式&#xff0c;用于对数据进行无序的分类。在定类数据…

快速读懂 C++ 中的 signed、unsigned、long 和 short 修饰符(C++复习向p7)

几种类型支持的修饰符 整型&#xff1a;signed、unsigned、long、short字符型&#xff1a;signed、unsigned双精度型&#xff1a;long 修饰符的含义 signed&#xff1a;标识变量可以存负数&#xff0c;整型默认就是这样 unsigned&#xff1a;相反的&#xff0c;不能存负数&a…