1、多线程:概念:1 进程:正在运行的程序2 线程:进程中一个程序执行的控制单元(执行路径)。P.S.1、一个进程中可以有多个执行路径,称之为多线程。2、一个进程中至少要有一个线程。3、开启多个线程是为了同时运行多部分代码,每一个线程都有自己运行的内容,这个内容可以称为线程要执行的任务。多线程的好处:解决多部分代码同时运行的问题。弊端:线程太多,会导致效率的降低。因为,多个程序同时运行,cpu需要在各个线程间进行不停的切换,这也需要消耗资源PS:JVM启动时,至少启动了两条线程:1 执行main函数的线程2 垃圾回收线程————————————————————————————————————————————————————————————————————class Test14 {public static void main(String[] args) {A a = new A();a = null;System.gc();// garbage collectionSystem.out.println(Thread.currentThread().getName() + " over");}}class A {@Overrideprotected void finalize() throws Throwable {System.out.println("A 的 finalize()被调用,调用进程是:"+ Thread.currentThread().getName());}}输出结果:main overA 的 finalize()被调用,调用进程是:Finalizer————————————————————————————————————————————————————————————————————
2、创建线程的方式:方法1 继承Thread类:1 定义类继承Thread类2 重写run方法3 直接创建Thread类的子类,并调用start()方法启动线程方法2 定义类实现Runnable接口1 定义类实现Runnable接口2 重写run方法3 创建实现Runnable接口的对象4 将对象作为参数传递给一个Thread类的对象,并调用该对象的start()方法启动线程实现Runnable接口的好处:1. 将线程的任务从线程的子类中分离出来,进行了单独的封装,更符合面向对象的思想。2. 避免了Java单继承的局限性。 所以,创建线程的第二种方式较为常用。PS:JVM创建的主线程的主任务定义在了主函数中,而自定义的线程其任务定义在run方法中,也就说run方法是封装了自定义线程运行任务的函数————————————————————————————————————————————————————————————————————public class CreatThreadDemo {public static void main(String[] args) {new MyThread().start();new Thread(new RunnableImpl()).start();}}class MyThread extends Thread {public void run() {while (true) {try {Thread.sleep(200);// 父类没有抛出异常,子类调用有抛异常的方法时,只能进行catch处理} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("我是继承Thread创建的进程:"+ Thread.currentThread().getName());}}}class RunnableImpl implements Runnable {public void run() {while (true) {try {Thread.sleep(200);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("我是实现了Runnable创建的进程:"+ Thread.currentThread().getName());}}}运行结果:我是实现了Runnable创建的进程:Thread-1我是继承Thread创建的进程:Thread-0我是继承Thread创建的进程:Thread-0我是实现了Runnable创建的进程:Thread-1我是继承Thread创建的进程:Thread-0我是实现了Runnable创建的进程:Thread-1我是实现了Runnable创建的进程:Thread-1————————————————————————————————————————————————————————————————————
3、线程安全:产生原因:1. 多个线程在操作共享的数据。2. 操作共享数据的线程代码有多条。当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。————————————————————————————————————————————————————————————————————public class ThreadSafetyDemo {public static void main(String[] args) {final Function f = new Function();new Thread() {public void run() {f.print();};}.start();new Thread() {public void run() {f.show();};}.start();}}class Function {public void print() {while (true) {for(char c:"骚年努力~~".toCharArray())System.out.print(c);System.out.println();}}public void show() {while (true) {for(char c:"Hello Java~~".toCharArray())System.out.print(c);System.out.println();}}}输出结果:Hello Java~~Hello Java~~Hel~            //线程安全,只打印了一部分骚年努力~~骚年努力~lo Java~~  线程安全,打印重叠Hello Java~~这里的公共资源是控制台。。。————————————————————————————————————————————————————————————————————4、线程安全的解决方案1、思路:将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程不可以参与运算。 必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。在java中,用同步代码块就可以解决这个问题。同步代码块的格式:synchronized(对象){需要被同步的代码;} 同步的好处:解决了线程的安全问题。同步的弊端:当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。同步的前提:必须有多个线程并使用同一个锁。PS:为了更容易实现多个线程共同使用一个锁,最好将对公共资源操作的代码,封装成方法,并作为同一个类的成员,然后通过run方法来调用这些操作资源的方法2、安全问题的另一种解决方案:同步代码块格式:在函数上加上synchronized修饰符即可。P.S.同步函数和同步代码块的区别:1. 同步函数的锁是固定的this。2. 同步代码块的锁是任意的对象。由于同步函数的锁是固定的this,同步代码块的锁是任意的对象,那么如果同步函数和同步代码块都使用this作为锁,就可以实现同步。静态的同步函数使用的锁是该函数所属字节码文件对象,可以用getClass方法获取,也可以用当前类名.class表示。————————————————————————————————————————————————————————————————————package ticket.demo;public class SellDemo2 {public static void main(String[] args) {MyRunnable m = new MyRunnable(new TicketShared());for (int i = 0; i < 3; i++) {new Thread(m).start();}}}class MyRunnable implements Runnable {private TicketShared t;public MyRunnable(TicketShared t) {super();this.t = t;}@Overridepublic void run() {while(true){try {Thread.sleep(50);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}t.dec();}}}class TicketShared {private int t = 100;public synchronized void dec() {if (t > 0) {t--;System.out.println(Thread.currentThread().getName() + "...售出一张,剩余"+ t);} else {System.out.println("票售完了~~");System.exit(0);}}}package ticket.demo;public class SellTicket {/*** 卖票程序*/private int j = 100;public static void main(String[] args) {SellTicket st = new SellTicket();Inc inc = st.new Inc();Dec dec = st.new Dec();new Thread(dec).start();new Thread(dec).start();new Thread(inc).start();new Thread(inc).start();}public synchronized void inc() {j++;System.out.println("加票:"+Thread.currentThread().getName() + ".."+j);}public synchronized void dec() {if(j>0){           System.out.println("售票:"+Thread.currentThread().getName() + ".."+j);j--;}}class Inc implements Runnable {@Overridepublic void run() {for (int i = 0; i < 100; i++) {inc();}}}class Dec implements Runnable {@Overridepublic void run() {for (int i = 0; i < 100; i++) {dec();}}}}————————————————————————————————————————————————————————————————————
5、单利设计模式//单利设计模式,单利即只能有一个实例,所以构造函数要私有化// 饿汉式:类初始化时就创建实例对象,线程安全class SingletonHungryType {private static final SingletonHungryType s = new SingletonHungryType();// 类初始化时就创建对象private SingletonHungryType() {}// 私有化,以实现单利public static SingletonHungryType getInstance() {// 返回实例对象return s;}}// 懒汉式:类初始化时不创建对象,等函数调用时,才创建。因为涉及可能存在多个线程同时调用创建对象的代码,所以线程不安全,需要实现同步class SingletonLazyType1 { // 同步代码块实现private static SingletonLazyType1 s = null;private SingletonLazyType1() {}public static SingletonLazyType1 getInstance() {if (s == null) {// 在这加判断能提高效率,因为当s已经建立后,线程可以直接跳过同步代码块,而不需要没次都等待锁// 这也就是使用同步代码块比同步函数效率高的原因synchronized (SingletonLazyType1.class) {if (null == s) {s = new SingletonLazyType1();}}}return s;}}class SingletonLazyType2 { // 同步函数实现private static SingletonLazyType2 s = null;private SingletonLazyType2() {}public static synchronized SingletonLazyType2 getInstance() {s = new SingletonLazyType2();return s;}}6、死锁/***        死锁演示*/public class DeadLock implements Runnable {private Object objA = new Object();private Object objB = new Object();//锁对象private boolean flag = false;//        DeadLock(boolean b){//                this.flag = b;//        }@Overridepublic void run() {// 相互嵌套是锁,可能会出现互相等待的现象导致死锁while(true){if(flag){synchronized(objA){//嵌套锁System.out.println("if A..."+Thread.currentThread().getName());synchronized(objB){System.out.println("if B..."+Thread.currentThread().getName());}flag = flag^true; //flag取反}}else{synchronized(objB){//嵌套锁System.out.println("else A..."+Thread.currentThread().getName());synchronized(objA){System.out.println("else B..."+Thread.currentThread().getName());}flag = flag^true;  //flag取反}}}}}public class DeadLockTest {/*** 用于死锁的测试*/public static void main(String[] args) {// TODO Auto-generated method stub//建立资源对象DeadLock d1 = new DeadLock();//新建两个进程new Thread(d1,"线程1").start();new Thread(d1,"线程2").start();}}运行结果:else A...线程1         //线程1 进入else,获取锁Belse B...线程1     if A...线程1     //线程1执行完else,释放B锁,进入if,获取锁A,在等待获取B锁else A...线程2        //线程2 持有B锁,在等待A锁//此时出现互相等待,即死锁现象,程序无法继续运行————————————————————————————————————————————————————————————————————import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;//死锁演示,出现嵌套锁时会出现互相等待对方释放锁资源现象public class DeadLockDemo {public static void main(String[] args) {final DeadLock dl = new DeadLock();new Thread() {public void run() {while (true)dl.show();};}.start();new Thread() {public void run() {while (true)dl.print();};}.start();}}class DeadLock {private Lock lock1 = new ReentrantLock();private Lock lock2 = new ReentrantLock();public void show() {lock1.lock();System.out.println(Thread.currentThread().getName()+"..show...lock1.lock();");lock2.lock();System.out.println(Thread.currentThread().getName()+"..show...lock2.lock();");lock2.unlock();lock1.unlock();}public void print() {lock2.lock();System.out.println(Thread.currentThread().getName()+"..print...lock2.lock();");lock1.lock();System.out.println(Thread.currentThread().getName()+"..ptint...lock1.lock();");lock1.unlock();lock2.unlock();}}运行:Thread-0..show...lock1.lock();Thread-0..show...lock2.lock();Thread-0..show...lock1.lock();Thread-1..print...lock2.lock();————————————————————————————————————————————————————————————————————
7、线程间通讯多个线程在处理统一资源,但是任务却不同,这时候就需要线程间通信。等待/唤醒机制涉及的方法:1. wait():让线程处于冻结状态,被wait的线程会被存储到线程池中。2. notify():唤醒线程池中的一个线程(任何一个都有可能)。3. notifyAll():唤醒线程池中的所有线程。P.S.1、这些方法都必须定义在同步中,因为这些方法是用于操作线程状态的方法。2、必须要明确到底操作的是哪个锁上的线程!3、wait和sleep区别?1)wait可以指定时间也可以不指定。sleep必须指定时间。2)在同步中时,对CPU的执行权和锁的处理不同。wait:释放执行权,释放锁。sleep:释放执行权,不释放锁。同步代码块就是对于锁的操作是隐式的。JDK1.5以后将同步和锁封装成了对象,并将操作锁的隐式方式定义到了该对象中,将隐式动作变成了显示动作。Lock接口:出现替代了同步代码块或者同步函数,将同步的隐式操作变成显示锁操作。同时更为灵活,可以一个锁上加上多组监视器。lock():获取锁。unlock():释放锁,为了防止异常出现,导致锁无法被关闭,所以锁的关闭动作要放在finally中。Condition接口:出现替代了Object中的wait、notify、notifyAll方法。将这些监视器方法单独进行了封装,变成Condition监视器对象,可以任意锁进行组合。Condition接口中的await方法对应于Object中的wait方法。Condition接口中的signal方法对应于Object中的notify方法。Condition接口中的signalAll方法对应于Object中的notifyAll方法。8、停止线程怎么控制线程的任务结束呢?任务中都会有循环结构,只要控制住循环就可以结束任务。控制循环通常就用定义标记来完成P.S.也可以使用stop方法停止线程,不过已经过时,不再使用。但是如果线程处于了冻结状态,无法读取标记,如何结束呢?答:可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备CPU的执行资格。强制动作会发生InterruptedException,一定要记得处理。

java 之 多线程相关推荐

  1. Oracle字符串转BooIean,利用Java的多线程技术实现数据库的访问.pdf

    利用Java的多线程技术实现数据库的访问.pdf 第 卷第 期 计算机应用 22 12 Voi .22 , No . 12 年 月 2002 12 Computer Appiications Dec ...

  2. Java 并发/多线程教程(四)-并发模型

    本系列译自jakob jenkov的Java并发多线程教程(本章节部分内容参考http://ifeve.com/并发编程模型),个人觉得很有收获.由于个人水平有限,不对之处还望矫正! 并发系统可以有多 ...

  3. LeetCode1117. Building H2O --Java解法--多线程保证执行顺序--AtomicInteger

    此文首发于我的个人博客:LeetCode 1117. Building H2O --Java解法–多线程保证执行顺序–AtomicInteger - zhang0peter的个人博客 LeetCode ...

  4. Java 并发/多线程教程(五)-相同线程

    本系列译自jakob jenkov的Java并发多线程教程,个人觉得很有收获.由于个人水平有限,不对之处还望矫正! 相同线程是一并发框架模型,是一个单线程系统向外扩展成多个单线程的系统.这样的结果就是 ...

  5. java 创建多线程_Java创建多线程

    Java创建多线程 下一节> 到目前为止,我们仅用到两个线程:主线程和一个子线程.然而,你的程序可以创建所需的更多线程.例如,下面的程序创建了三个子线程: // Create multiple ...

  6. Java接口多线程并发测试 (一)

    本文为作者原创,禁止转载,违者必究法律责任!!! 本文为作者原创,禁止转载,违者必究法律责任!!! Java接口多线程并发测试 一,首先写一个接口post 请求代码: import org.apach ...

  7. Java的多线程和线程池的使用,你真的清楚了吗?

    Java的多线程和线程池的使用 多线程大大提高程序运行效率,我们在开发过程中经常会开启一个线程来执行一些费时的任务.开启一个线程有4种方式,在下面的文章我将详细的去讲解. 继承Thread 继承Thr ...

  8. 《Java程序设计》实验报告——Java的多线程机制

    浙江理工大学 <Java程序设计>  实验报告  20 19-20 20学年第 1学期      学  院 信息学院 班  级 计算机科学与技术18(3) 姓  名 申屠志刚 学  号 2 ...

  9. JAVA 10(多线程)

    创建线程: 通过对java.lang包的查找,继承Thread类可以创建线程 1,建立类继承Thread类 2,复写Thread中的ran方法. 3,调用线程的start()方法,该方法的作用是,启动 ...

  10. Java中多线程的性能比较

    Java中有多种用于多线程的技术. 可以通过同步关键字,锁或原子变量来并行化Java中的一段代码. 这篇文章将比较使用synced关键字ReentrantLock,getAndIncrement()以 ...

最新文章

  1. vue 源码学习(二) 实例初始化和挂载过程
  2. Active Record
  3. android 模拟器配置上网_10 款主机模拟器,让你畅玩全球大作,嗨到飞起
  4. WinAPI: CloseFigure
  5. 运行一个程序时如何打印出执行程序的时间
  6. BCrypt管理员登录密码验证
  7. OOP-ECMAScript - 深入理解Javascript
  8. Opencv4.5.5 + Opencv4.5.5_contrib 图像拼接
  9. App后台开发运维和架构实践学习总结(9)——三种常见的API设计错误及解决方案
  10. Spring+CXF的WebServices简单示例
  11. IDA保存修改的寄存器值
  12. 拓端tecdat|R语言使用Rasch模型分析学生答题能力
  13. keil教程之创建基础软件工程
  14. ILSVRC2016
  15. 前端js生成自定义内容的PDF及word文件的实现
  16. 二分+秦九韶算法 求凸点
  17. 高速学习的奥秘:大脑的不同学习机制
  18. (已解决)网页不显示数学公式||只显示源码
  19. 2023年直播行业的困境是什么?未来有哪些发展趋势?
  20. 二元隐函数求二阶偏导_高数,隐函数求二阶偏导。f(x-y,yz)确定了z=(x,y),f具有二阶连续偏导数,求...

热门文章

  1. servlet实现http通信基础
  2. ibatis动态查询条件(转载待完善)
  3. Unix调试的瑞士军刀:lsof
  4. 配置MPLS BGP ××× 出现单边的故障
  5. 可视化的数据结构和算法
  6. DNN安装报错-The stored procedure 'dbo.GetPortalAliasByPortalID' doesn't exist.如何解决
  7. Roger Ver:比特币已经过时,以太坊和比特币现金将实现超越
  8. git常用命令和场景
  9. Windows Server 2008 R2 如何启动内核调试
  10. 脊柱是导致身体生病的重要原因