Java多线程
Java线程简介
进程
本身可以看成是系统资源和程序代码的执行位置的集合。在操作系统中,每个应用程序的执行都在操作系统内核中登记一个进程标志,操作系统根据分配的标志对应用程序的执行进行调度和系统资源分配。每个进程都有自己的内存单元,进程之间是相互独立的,一个进程一般不允许访问其他进程的内存空间,因此,进程间通信非常困难。
线程
是比进程更小的执行单位。如果将进程概念一分为二,则进程中的系统资源,可以看成是一个静态的对象;而程序代码的执行位置,可以看成一个动态的对象,这个动态的部分就是线程。进程在执行过程中拥有独立的内存单元,而多个线程可以共享内存,线程之间的通信相对的进程比较容易解决,从而极大地提高了程序的运行效率,通常一个进程可以包含多个线程。
Java多线程
多线程就是多个线程的集合。就是一个程序(进程)中同时执行一个以上的线程,一个线程的执行不必等待另一个线程执行完才执行,所有线程都可以发生在同一个时刻。但JVM仍然认为每个线程不是独立的应用,来实现进程的调度和管理以及资源分配,而是将这个包含多个线程的程序作为一个系统进程处理;这样的Java程序被称为多线程应用。
多线程程序中,多个线程共享内存,从而在某种情况下使用多线程可以提高程序的运行效率。
多线程程序通常比较复杂,由于多个线程共享一个jvm内存,从而会涉及到数据共享及操作的冲突等问题,因此在非必需情况下要谨慎选择使用多线程方式处理业务逻辑。
Thread线程类及常用方法
java.lang.Thread类是线程类型,任何此类或其子类对象都是一个线程对象都是一个线程对象
任何一个Thread实例调用start方法将启动运行一个线程
Thread类中的run方法是线程启动后自动执行的业务方法
Thread常用构造器
public Thread() //一个普通的thread,没有名字,系统自动生成名字
public Thread(Runnable target) //新增了一个Runnable接口,作用是可以使多个thread执行同一个代码块
public Thread(Runnable target,String name) //比第二个方法多了一个字符串参数,给当前thread起一个自定义的线程名字
线程的生命周期
第一阶段:新建状态(此时线程还没有运行)
第二阶段:运行状态(线程开始运行并自动执行run方法)
第三阶段:中断状态(多种原因使线程处于终止)
第四阶段:死亡状态(释放线程对象,不能再恢复运行)
Thread常用方法1
public void start() 启动线程
public void run() 执行线程的核心业务功能
public static void sleep(long millis)throws InterruptedException 线程休眠,millis是毫秒,线程休眠以后会让出CPU资源,时间结束以后会自动苏醒
public void interrupt() 中断线程当前状态
public final void join() throws InterruptedException 线程联合,当前线程独占CPU资源
Thread常用方法2
public boolean isInterrupted() 判断测试线程是否已经中断
public final boolean isAlive() 判断测试线程是否处于活动状态,只有未调用start之前和死亡以后返回值是false
public static void yield() 暂停当前线程,执行其它线程
public final String getName() 获取线程名称
public final int getPriority() 获取线程的优先级
Thread 常用方法3
public final void setName(String name) 设置线程的名称
public final void setPriority(int newPriority) 设置线程的优先级
Runnable线程接口
Runnable接口是Java中一个线程接口,此接口提供一个唯一的run方法,Runnable接口的主要作用就是可以让多个Thread的实例共享此接口的run方法,达到一个线程间通信更加方便的目的。
线程之间的通信
Java使我们可以创建多个线程,在处理多线程问题时,我们必须注意这样一个问题,当两个或多个线程同时访问同一个变量,并且一个线程需要修改这个变量。我们应对这样的问题作出处理,否则可能发生混乱,比如一个工资管理负责人正在修改雇员的工资表,而一些雇员也正在领取工资,如果容许这样做必然出现混乱。因此,工资管理负责人正在修改工资表时包括他喝茶休息一会,将不容许任何雇员领取工资,也就是说这些雇员必须等待。
在处理线程同步是,要做的第一件事就是要把修改数据的方法用关键字synchronized来修饰,一个方法使用关键synchronized修饰后,当一个线程A使用这个方法时,其他线程想使用这个方法时就必须等待,直到线程A使用完该方法。
同步代码块
被同步的代码块在一个线程对象进行访问时,其他线程是没有访问权限的,只有这个当前线程对象完全执行完了这个代码块,释放了同步锁,其它线程才可以访问这个代码块。
对象同步锁
- 对共享对象的访问必须同步,叫做条件变量。
- Java语言允许通过监视器使用条件变量实现线程同步
- 监视器阻止两个线程同时访问同一个条件变量,它如同锁一样作用在数据上。
- 线程一进入卖票方法时获得监视器(加锁),当线程1的方法执行完毕后释放监视器(开锁),线程2的卖票方法才能进入。
方法同步锁
用synchronized来标识的方法为互斥方法。表明在任何给定的时候只能有一个线程可以执行该方法(方法同步锁)。
package main; import Objects.Empolyee; import until.EmployeeManager; import until.SynMethod; import java.util.ArrayList; import java.util.List; public class TestEmployee { public static void main(String[] args) throws InterruptedException { //new一个员工实体类 Empolyee empolyee = new Empolyee(); //new一个员工方法类 EmployeeManager employeeManager = new EmployeeManager(); //new一个线程类 SynMethod synMethod = new SynMethod(empolyee); empolyee.setEmpID("110380"); empolyee.setEmpName("曾誉"); empolyee.setEmpAge(25); //实例化3个线程,分别用来新增用户,更改用户,删除用户 Thread addEmp = new Thread(synMethod,"新增用户"); Thread changeEmp = new Thread(synMethod,"修改用户"); Thread deleteEmp = new Thread(synMethod,"删除用户"); //启动线程 addEmp.setPriority(Thread.MAX_PRIORITY); deleteEmp.setPriority(Thread.MIN_PRIORITY); addEmp.start(); changeEmp.start(); deleteEmp.start(); //join()方法就是指调用该方法的线程在执行完run()方法后,再执行join方法后面的代码,即将两个线程合并,用于实现同步控制。 addEmp.join(); changeEmp.join(); deleteEmp.join(); //遍历获取对象数组里的内容 for (Empolyee emp2:employeeManager.getList()){ System.out.println( "员工姓名 "+emp2.getEmpName() +"\n员工id "+emp2.getEmpID() +"\n员工年龄 "+emp2.getEmpAge() ); } } }
package Objects; public class Empolyee { private String empID; private String empName; private String empSex; private int empAge; public String getEmpID() { return empID; } public void setEmpID(String empID) { this.empID = empID; } public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } public String getEmpSex() { return empSex; } public void setEmpSex(String empSex) { this.empSex = empSex; } public int getEmpAge() { return empAge; } public void setEmpAge(int empAge) { this.empAge = empAge; } }
package until; import Objects.Empolyee; import java.util.ArrayList; import java.util.List; public class EmployeeManager { //定义一个集合模拟数据库表 static List<Empolyee> list = new ArrayList<>(); public List<Empolyee> addEmployee(Empolyee empolyee){ list.add(empolyee); return list; } public List<Empolyee> changeEmployee(Empolyee empolyee){ list.set(0,empolyee); return list; } public List<Empolyee> deleteEmployee(){ list.remove(1); return list; } public List<Empolyee> getList() { return list; } }
package until; import Objects.Empolyee; import java.util.ArrayList; import java.util.List; public class SynMethod implements Runnable{ //new一个employee方法类 EmployeeManager employeeManager = new EmployeeManager(); //new一个employee类 Empolyee emp = new Empolyee(); //定义一个集合模拟数据库表 List<Empolyee> list = new ArrayList<>(); public SynMethod(Empolyee empolyee){ this.emp = empolyee; } @Override public void run() { addEmployee(); } //定义一个synchronized标识的方法同步锁互斥方法 public synchronized void addEmployee(){ //获取一个当前的线程对象 Thread t = Thread.currentThread(); for (int i=1;i<=5;i++){ if (t.getName().equals("新增用户")){ employeeManager.addEmployee(emp); System.out.println("正在新增用户"+emp.getEmpName()); } if (t.getName().equals("修改用户")){ employeeManager.changeEmployee(emp); System.out.println("正在修改用户"+emp.getEmpName()); } if (t.getName().equals("删除用户")){ employeeManager.deleteEmployee(); System.out.println("正在删除第2个用户"); break; } } } }