黑马程序员_java多线程

本文介绍了Java中多线程的基本概念,包括进程与线程的区别,实现多线程的两种方式:继承Thread类和实现Runnable接口。此外还探讨了多线程同步的问题,并通过售票程序的案例展示了如何解决线程安全问题。

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------


 

Blog_3_1  多线程基础概念

为了可以让不同的程序块一起运行,让程序运行更为顺畅,同时也可达到多任务处理的目的,java引入了多线程的概念。

进程: 进程是程序的一次动态执行过程, 它经历了从代码加载、执行到执行完毕的一个完整过程,这个过程也是进程本身从产生、发展到最终消亡的过程。

线程:程序内部的代码执行路径,一个进程可以有多条执行路径。

Blog_3_2  实现多线程的两种方法

Java中提供了Thread类和Runnable接口,来实现多线程,下面分别用Thread和Runnable来实现多线程。

(1)  通过继承Thread类来实现多线程

通过继承Thread类来实现多线程的步骤有二步如下:

(a).编写一个类并继承Thread类并重写run方法,其中run方法中的代码就是多线程运算的代码块,如下:

public classMyThread extendsThread {
   @Override
   public void run() {
      for (int x = 0; x < 1000;x++) {
         System.out.println(x);
      }
   }
}

(b).创建MyThread类的对象并调用start()方法开启多线程,如下

      MyThread my1 =new MyThread();//创建了MyThread对象
      MyThread my2 =new MyThread();
      my1.start();//开启多线程
   my2.start();

(2)  通过Runnable接口实现多线程

(a)   自定义类MyRunnable实现Runnable接口并重写run()方法

public classMyRunnable implementsRunnable {
   @Override
   public void run() {
      for (int x = 0; x < 100; x++){
         System.out.println(Thread.currentThread().getName()+"---"+ x);
      }
   }
}

(b)   创建MyRunnable类的对象

MyRunnablemy = new MyRunnable();

(c)    创建Thread类的对象,把MyRunnable类的对象作为构造参数传递

Thread t1 = new  Thread(my, "线程1");

Thread t2 = new  Thread(my, "线程2");

(d)   调用start()方法开启多线程

t1.start();

t2.start();

(3)  两种机制的的特点及比较

A、适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码、数据有效分离,较好地体现了面向对象的设计思想。

B、可以避免由于Java的单继承特性带来的局限。开发中经常碰到这样一种情况,即:当要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么就只能采用实现Runnable接口的方式了。

C、增强了程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。当多个线程的执行代码来自同一个类的实例时,即称它们共享相同的代码。多个线程可以操作相同的数据,与它们的代码无关。当共享访问相同的对象时,即共享相同的数据。当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例。

Blog_3_3  多线程的同步

(1) 多线程不同步的原因分析

通过一个买票的实例来分析出现多线程不同步的原因:

书写一个Ticket类实现Runnable接口

public class Ticket implements Runnable {
   private int tickets = 100;
 
   @Override
   public void run() {
      while (true) {
         if (tickets > 0) {
   System.out.println(Thread.currentThread().getName() +"正在出售第"+tickets + "张票");
ticket--;
         }
      }
   }
}

Ticket的测试类:

public class TicketDemo {
   public static void main(String[] args) {
      Ticket t = new Ticket();
      Thread t1 = new Thread(t,"窗口1");
      Thread t2 = new Thread(t,"窗口2");
      Thread t3 = new Thread(t,"窗口3");
      Thread t4 = new Thread(t,"窗口4")
      t1.start();
      t2.start();
      t3.start();
      t4.start();
   }
}

上面程序打印出来的结果是:

……..

窗口1正在出售第2张票

窗口4正在出售第1张票

窗口1正在出售第0张票

窗口2正在出售第-1张票

窗口3正在出售第-2张票

发现打印结果出现了0,-1,-2的不符合常规的结果,是怎样产生这样的结果呢,下面来分析:

当ticket只剩1张时:

   假设“窗口1”首先抢到了cpu的执行权,当执行到ticket--,前一步时被“窗口2”抢到了执行权,此时ticket值为1,“窗口2”也能进入if (tickets > 0)内部,当“窗口1”再次抢到cpu执行权时,打印出来的即是窗口1正在出售第0张票,当“窗口2”接着运行打印代码时结果是窗口2正在出售第-1张票。同理,窗口3也能打印出窗口3正在出售第-2张票。综上所述产生线程不同步的条件有三个:    

A:多线程程序(存在在同一时间抢夺cup执行权的情况)

      B:有共享数据

      C:共享数据被多条语句操作

(2)  两种同步线程的方法

①使用synchronized为存在线程安全问题的代码“上锁”。

如上面的代码可以这样处理使其同步:

public class Ticket implements Runnable {
   private int tickets = 100;
   Object obj=new Object();
   @Override
   public void run() {
      while (true) {
         synchronized(obj){  
/*使用synchronized关键字为存在线程安全问题的代码上锁,括号内的对象一样,则代表锁是同一把。如果不同线程调用run方法时,此处的obj不是同一个对象的话,则无法使线程同步*/
         if (tickets > 0) {
   System.out.println(Thread.currentThread().getName() +"正在出售第"+tickets + "张票");
ticket--;
         }
}
      }
   }
}

②在方法声明部分使用 synchronized关键字,使不安全的线程同步,如

public class Ticket implements Runnable {
   private int tickets = 100;
   @Override
   Public synchronized void run() {
         while (true) {
         if (tickets > 0) {
            System.out.println(Thread.currentThread().getName() +"正在出售第"+ (tickets--) +"张票");
         }
      }
   }
}

在方法声明上加了synchronized关键字,同样可以达到使有线程安全的代码同步。

(3)  一个死锁的代码

一旦有多个进程,且它们都要争用对多个锁的独占访问,那么就有可能发生死锁。如果有一组进程或线程,其中每个都在等待一个只有其它进程或线程才可以执行的操作,那么就称它们被死锁了,如下面代码:

public class MyLock {
   public static final Object lockA =new Object();
   public static final Object lockB =new Object();
}
public class DieLock extends Thread {
   private boolean flag;
 
   public DieLock(boolean flag) {
      this.flag = flag;
   }
   @Override
   public void run() {
      if (flag) {
         while (true) {
            synchronized (MyLock.lockA) {
            System.out.println("iflockA");// t1的执行权没有了
                synchronized (MyLock.lockB) {
                   System.out.println("iflockB");
                }
            }
         }
      } else {
         while (true) {
            synchronized (MyLock.lockB) {
                System.out.println("elselockB");// t2的执行权没有了
                synchronized (MyLock.lockA) {
                   System.out.println("elselockA");
                }
            }
         }
      }
   }
}
public class DieLockDemo {
   public static void main(String[] args) {
      DieLock dl1 = new DieLock(true);
      DieLock dl2 = new DieLock(false);
      dl1.start();
      dl2.start();
   }
}

Blog_3_4  多线程间的通讯

Java是通过Object类的wait、notify、notifyAll这几个方法来实现线程间的通信的,又因为所有的类都是从Object继承的,所以任何类都可以直接使用这些方法。

wait:告诉当前线程放弃监视器并进入睡眠状态,直到其它线程进入同一监视器并调用notify为止。

notify:唤醒同一对象监视器中调用wait的第一个线程。类似排队买票,一个人买完之后,后面的人可以继续买。

notifyAll:唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。

 

----------------------- android培训java培训、java学习型技术博客、期待与您交流! ----------------------

详情请查看:http://edu.youkuaiyun.com/heima



 

内容概要:本文设计了一种基于PLC的全自动洗衣机控制系统内容概要:本文设计了一种,采用三菱FX基于PLC的全自动洗衣机控制系统,采用3U-32MT型PLC作为三菱FX3U核心控制器,替代传统继-32MT电器控制方式,提升了型PLC作为系统的稳定性与自动化核心控制器,替代水平。系统具备传统继电器控制方式高/低水,实现洗衣机工作位选择、柔和过程的自动化控制/标准洗衣模式切换。系统具备高、暂停加衣、低水位选择、手动脱水及和柔和、标准两种蜂鸣提示等功能洗衣模式,支持,通过GX Works2软件编写梯形图程序,实现进洗衣过程中暂停添加水、洗涤、排水衣物,并增加了手动脱水功能和、脱水等工序蜂鸣器提示的自动循环控制功能,提升了使用的,并引入MCGS组便捷性与灵活性态软件实现人机交互界面监控。控制系统通过GX。硬件设计包括 Works2软件进行主电路、PLC接梯形图编程线与关键元,完成了启动、进水器件选型,软件、正反转洗涤部分完成I/O分配、排水、脱、逻辑流程规划水等工序的逻辑及各功能模块梯设计,并实现了大形图编程。循环与小循环的嵌; 适合人群:自动化套控制流程。此外、电气工程及相关,还利用MCGS组态软件构建专业本科学生,具备PL了人机交互C基础知识和梯界面,实现对洗衣机形图编程能力的运行状态的监控与操作。整体设计涵盖了初级工程技术人员。硬件选型、; 使用场景及目标:I/O分配、电路接线、程序逻辑设计及组①掌握PLC在态监控等多个方面家电自动化控制中的应用方法;②学习,体现了PLC在工业自动化控制中的高效全自动洗衣机控制系统的性与可靠性。;软硬件设计流程 适合人群:电气;③实践工程、自动化及相关MCGS组态软件与PLC的专业的本科生、初级通信与联调工程技术人员以及从事;④完成PLC控制系统开发毕业设计或工业的学习者;具备控制项目开发参考一定PLC基础知识。; 阅读和梯形图建议:建议结合三菱编程能力的人员GX Works2仿真更为适宜。; 使用场景及目标:①应用于环境与MCGS组态平台进行程序高校毕业设计或调试与运行验证课程项目,帮助学生掌握PLC控制系统的设计,重点关注I/O分配逻辑、梯形图与实现方法;②为工业自动化领域互锁机制及循环控制结构的设计中似家电控制系统的开发提供参考方案;③思路,深入理解PL通过实际案例理解C在实际工程项目PLC在电机中的应用全过程。控制、时间循环、互锁保护、手动干预等方面的应用逻辑。; 阅读建议:建议结合三菱GX Works2编程软件和MCGS组态软件同步实践,重点理解梯形图程序中各环节的时序逻辑与互锁机制,关注I/O分配与硬件接线的对应关系,并尝试在仿真环境中调试程序以加深对全自动洗衣机控制流程的理解。
### 关于Java多线程的学习笔记 #### 1. 实现多线程的方式 在Java中,可以通过继承`Thread`实现`Runnable`接口来创建多线程程序[^1]。 对于通过继承`Thread`的方法: ```java class MyThread extends Thread { public void run() { System.out.println("MyThread running"); } } ``` 而采用实现`Runnable`接口的形式则更为灵活,因为这不会占用已有的继承机会,并允许共享同一个对象实例给多个线程使用: ```java class MyRunnable implements Runnable { @Override public void run() { System.out.println("MyRunnable running"); } } // 使用方式如下: new Thread(new MyRunnable()).start(); ``` #### 2. 创建并启动线程 一旦定义好了线程体之后,就可以利用`Thread`的构造函数传入该线程体,并调用其`start()`方法开启新线程执行任务。需要注意的是应该避免直接调用`run()`方法,因为它会在当前线程内顺序执行而不是新开一个独立的工作单元。 ```java public class Main { public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); thread.start(); // 正确做法 // 错误示范:thread.run(); } } ``` #### 3. 线程同步机制 当涉及到资源共享时,可能会遇到竞态条件等问题。为了确保数据一致性,在访问临界区资源前应当加锁保护。可以借助`synchronized`关键字或者更高级别的并发工具包如`ReentrantLock`来进行操作控制。 ```java synchronized (lockObject) { // 对共享变量的操作... } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值