多线程在测试中的应用
1、Java 多线程
什么是程序?
安装在磁盘上的一段指令集合,它是静态的概念。
2、什么是进程?
它是运行中的程序,是动态的概念。每个进程有独立的资源空间。
3、什么是线程?
线程,又称为轻量级进程,是程序执行流的最小单元,是程序中一个单一的顺序控制流程。线程是进程中的一个实体,是被系统独立调度和分派的基本单位。
4、什么是多线程?
多线程则指的是在单个程序中可以同时运行多个不同的线程执行不同的任务。
5、多线程的特点:
一个进程可以包含一个或多个线程。
一个程序实现多个代码同时交替运行就要产生多个线程。
线程本身不拥有系统资源,与同属一个进程的其它线程共享所在进程所拥有的资源。
同一个进程中多个线程之间可以并发执行。CPU会随机抽出时间,让我们的程序一会做这件事情,一会做另外一件事情。
多线程的目的:
就是“最大限度的利用CPU资源”,当某一线程的处理不需要占用CPU而只和I/O等资源打交道时,让需要占用CPU资源的其它线程有机会获得CPU资源。从根本上说,这就是多线程编程的目的。
Java运行系统在很多方面依赖线程,所有的类库设计都考虑到多线程。Java 是纯面向对象语言,Java 的线程模型也是面向对象的。
6、多线程创建
第一种方式:通过继承Thread 类创建线程
普通JAVA类如继承自Thread类,就成为一个线程类,并可通过该类的start方法来启动线程,执行线程代码。
Thread 类的子类可直接实例化,但在子类中必须覆盖Run方法才能真正运行线程的代码。
publicclassHelloThreadDemo {
publicstaticvoidmain(String[] args) {
HelloThread h1 = newHelloThread("A");
//h1.setName("线程1");
h1.start();
HelloThread h2 = newHelloThread("B");
//h2.setName("线程2");
h2.start();
/* for (intj=0; j<3; j++) {
new HelloThread().start();
}*/
}
}
classHelloThread extends Thread {
public HelloThread (Stringname) {
super(name);
}
publicvoid run() {
for (inti=0;i<3;i++) {
System.out.println(this.getName()+":" +i);
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
// TODOAuto-generated catch block
e.printStackTrace();
}
}
}
}
第二种方式:通过实现Runnable 接口创建线程
实现Runnable 接口的类必须借助Thread类才能创建线程。通过Runnable 接口创建线程分为两步:
创建实现Runnable 接口的类的实例;
创建一个Thread 类对象,将第一步实例化得到Runnable 对象作为参数传入Thread 类的构造方法。
通过Thread类的start方法启动线程。
publicclassHelloRunnableDemo {
publicstaticvoidmain(String[] args) {
HelloRunnable helloRunnable = newHelloRunnable();
Thread t1 = newThread(helloRunnable,"A");
t1.start();
Thread t2 = newThread(helloRunnable,"B");
t2.start();
}
}
classHelloRunnable implements Runnable {
publicvoid run() {
for (inti=0;i<3;i++) {
System.out.println(Thread.currentThread().getName()+":" +i);
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
7、需求:使用多线程完成车票购买流程,一号窗口和二号窗口,火车票一共为5张车票。
packagecom.iotek.threadtest;
publicclassSharedDataThreadDemo {
publicstaticvoidmain(String[] args) {
TickeRunnable runnable = newTickeRunnable();
Thread t1 = newThread(runnable,"一号窗口");
t1.start();
Thread t2 = newThread(runnable,"二号窗口");
t2.start();
}
}
classTickeRunnable implements Runnable {
privateintticket=5;
publicvoid run() {
while (true) {
System.out.println(Thread.currentThread().getName()+ ":" + (ticket--));
if (ticket < 1) {
break;
}
}
}
}
8、为什么需要同步?
线程同步是为了防止多个线程访问一个数据对象时,对数据造成破坏;
线程的同步是保证多线程安全访问竞争资源的一种手段。
同步和锁
Java中每个对象都有一个内置锁;
当程序运行到非静的synchronized同步方法上时,自动获得与正在执行代码的当前实例(this 实例)有关的锁;当程序运行到synchronized同步代码块时,自动获得锁定对象的锁;
获得一个对象的锁也称为获取锁、锁定对象、在对象上锁定或在对象上同步。当程序运行到synchronized同步方法或代码块时该对象锁才起作用;
一个对象只有一个锁。所以,如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放锁。这也意味任何其他线程都不能进入synchronized方法或代码块,直到该锁被释放。释放锁是指持锁线程退出了synchronized同步方法或代码块。
对于同步,一般而言在Java 代码中需要完成两个操作;
把竞争访问的资源标识为private
同步那些访问资源的代码,使用synchronized关键字来修饰方法或代码块。当synchronized方法执行完或发生异常时,会自动释放锁。
9、需求:
某银行卡账号有500元现金。一个人拿着存折去取钱,同时另一个人拿着卡去ATM上取钱,各自取钱400元。
要求取钱过程中不能出现资源竞争:比如400元被取出两次、银行卡的账目不能小于0等。
publicclass BankDemo{
publicstaticvoidmain(String[] args) {
Bank bank = new Bank();
BankThread p1 = newBankThread(bank);
p1.start();
BankThread p2 = newBankThread(bank);
p2.start();
}
}
classBankThread extends Thread {
private Bank bank=null;
public BankThread(Bankbank){
this.bank = bank;
}
publicvoid run() {
System.out.println("取钱:" + bank.getMoney(400));
}
}
class Bank {
privateintmoney=500;
publicsynchronizedint getMoney(int number) {
if(number<0) {
return -1;
}elseif(money<0) {
return -2;
}elseif(number-money>0) {
return -3;
}else {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
// TODOAuto-generated catch block
e.printStackTrace();
}
money-=number;
System.out.println("余额:" + money);
}
returnnumber;
}
}
10、并发在测试中应用:
packagecom.thread.test;
importjava.util.concurrent.CyclicBarrier;
importjava.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
publicclass test1{
publicstaticvoidmain(String[] args) {
int count =10;
CyclicBarrier cyclicBarrier = newCyclicBarrier(count);
ExecutorService executorService =Executors.newFixedThreadPool(count);
for (int i = 0; i< count; i++)
executorService.execute(new test1().newTask(cyclicBarrier));
executorService.shutdown();
while(!executorService.isTerminated()) {
try {
Thread.sleep(10);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
publicclass Task implements Runnable{
private CyclicBarriercyclicBarrier;
publicTask(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier =cyclicBarrier;
}
@Override
publicvoid run(){
try {
// 等待所有任务准备就绪
cyclicBarrier.await();
// 需要测试的内容
} catch(Exception e) {
e.printStackTrace();
}
}
}
}