多线程在软件开发中用得很多,现在几乎所有的软件都用到了多线程,如:QQ、迅雷、eclipe集成开发环境等。
什么是多线程?
当一个程序启动后就是一个进程,可以理解进程就是CPU的一个执行流程,而多线程就是在一个进程内执行多个线程,相当于在一个执行流程内开辟多个执行序列,举个例子:一个服务员每天要做端菜、洗碗、拖地等事情,每件事情可以理解为一个执行流程,让他开始洗碗那么他必须要把碗洗完了才能做其他的事情(流程),这样效率就很低,如果在他正在洗碗的时候能够做其它事情那么就很高效了,如他正在洗碗,这时让他去端菜,那就暂时停止洗碗去端菜,菜端完了继续洗碗。
时间片:
简单理解就是分配给线程的执行时间,实际上线程在微观上是串行执行的,也就是一个个执行,但是系统给每个线程都分配的执行时间,
如:
线程1 分配10ms的执行时间
线程2 分配10ms的执行时间
由于时间很短给人的感觉就是多个线程在一起执行。
线程的生命周期:
一个线程从创建、启动、结束有几种状态。
1.新建 线程已经准备就绪还没启动
2.运行 线程正在执行(在分配的时间内)
3.阻塞 线程已经启动但没有获得执行时间而处于等待队列中
4.结束 线程已经执行完毕并释放相关资源
Java实现多线程的3种方式:
1.让一个需要实现线程操作的类继承至Thread类,并重写父类的run方法
2.让一个需要实现线程操作的类实现Runnable接口
3.使用Timer和TimerTask组合
第一种实现方法:
package mypackage;
/**
* 继承至Thread类使能够执行线程
* @author dream
*
*/
public class MyThread extends Thread
{
public static void main(String[] args)
{
MyThread myth=new MyThread();
myth.start();
System.out.println("主线程");
}
//线程的调用run方法执行
public void run()
{
int n=10;
while(true)
{
if(n>0)
{
try
{
System.out.println(n);
n--;
Thread.sleep(1000);
}
catch(Exception ex)
{
}
}
}
}
}
第二种实现方法:
package mypackage;
/**
* 实现Runnable接口执行线程操作
* @author dream
*
*/
public class MyThread1 implements Runnable
{
public static void main(String[] args)
{
MyThread myth=new MyThread();
myth.start();
System.out.println("主线程");
}
public void run()
{
int n=10;
while(true)
{
if(n>0)
{
try
{
System.out.println(n);
n--;
Thread.sleep(1000);
}
catch(Exception ex)
{
}
}
}
}
}
第三种实现方法:
package mypackage;
import java.util.Timer;
import java.util.TimerTask;
public class MyThread2 extends TimerTask
{
public static void main(String[] args)
{
MyThread2 myth=new MyThread2();
Timer timer=new Timer();
timer.schedule(myth, 0);//启动线程
System.out.println("主线程");
}
public void run()
{
int n=10;
while(true)
{
if(n>0)
{
try
{
System.out.println(n);
n--;
Thread.sleep(1000);
}
catch(Exception ex)
{
}
}
}
}
}
多线程遇到的问题及处理:
多线程虽然能够使软件高效运行,但用得不好会带来负面效果
如一个变量a=10,同时启动3个线程来读取它的值,每读取一次则值减一,这就有一个问题,3个线程在各自的时间段里执行,但操作的变量a是共有的
线程1 使a的值减一 正常情况应该a=9了,如果线程2已经使a减一了那么这就会出问题了。
下面是一段有问题的代码:
//---------threaddemo.java
package mypackage;
public class threaddemo
{
public int money=20;
}
//OpeatorMoney.java
package mypackage;
public class OpeatorMoney extends Thread
{
threaddemo demo;
private String threadname;
public OpeatorMoney(threaddemo demo1,String name)
{
this.demo=demo1;
this.threadname=name;
}
public void run()
{
while(true)
{
try
{
if(demo.money>0)
{
System.out.println("线程:"+this.threadname+"---"+demo.money);
demo.money--;
}
else
{
break;
}
}
catch(Exception ex){}
}
}
}
//ThreadTest.java
package demo1;
import java.util.Timer;
import mypackage.*;
public class ThreadTest {
/**
* @param args
*/
public static void main(String[] args)
{
threaddemo demo=new threaddemo();
OpeatorMoney opm1=new OpeatorMoney(demo, "线程1");
OpeatorMoney opm2=new OpeatorMoney(demo, "线程2");
OpeatorMoney opm3=new OpeatorMoney(demo, "线程3");
opm1.start();
opm2.start();
opm3.start();
}
private static void Show(String msg)
{
System.out.println(msg);
}
}
这段代码会输出:
线程:线程1---20
线程:线程2---20
线程:线程2---19
线程:线程1---18
线程:线程1---16
线程:线程1---15
线程:线程1---14
线程:线程1---13
线程:线程1---12
线程:线程1---11
线程:线程1---10
线程:线程1---9
线程:线程1---8
线程:线程1---7
线程:线程1---6
线程:线程1---5
线程:线程1---4
线程:线程1---3
线程:线程1---2
线程:线程1---1
线程:线程3---17
线程:线程2---17
这显然是有问题的,可以通过互斥解决这个问题,也就是当一个线程正在操作这个代码的时候其它线程必须等待:
一个案例代码:
//----Account.java
package mypackage;
/**
* 模拟银行帐号的类
* @author dream
*
*/
public class Account
{
int money=0;//账户余额
//取钱
public synchronized void GetMoney()
{
System.out.println("准备取钱....");
try
{
//检查是否有钱
if(this.money==0)
{
wait();//账户没钱等待家长存钱
}
money=money-50;
System.out.println("剩余:"+this.money);
notify();//通知家长存钱
}
catch(Exception ex){}
}
//存钱
public synchronized void SetMoney()
{
try
{
System.out.println("准备取钱....");
if(this.money!=0)
{
wait();//如果孩子账户还有钱,则等待
}
money=200;
System.out.println("存入"+this.money);
notify();//通知孩子取钱
}
catch(Exception ex){}
}
}
//----Parent.java
package mypackage;
/**
* 模拟家长的类
* @author dream
*
*/
public class Parent extends Thread
{
private Account account;
public Parent(Account a)
{
this.account=a;
start();
}
public void run()
{
try
{
while(true)
{
Thread.sleep(10000);
this.account.SetMoney();
}
}
catch(Exception ex){}
}
}
//-----ThreadTest.java
package demo1;
import java.util.Timer;
import mypackage.*;
public class ThreadTest {
/**
* @param args
*/
public static void main(String[] args)
{
Account a=new Account();
Parent p1=new Parent(a);
Student stu1=new Student(a);
}
private static void Show(String msg)
{
System.out.println(msg);
}
}
输出: