------- android培训、java培训、期待与您交流! ----------
一 进程和线程概念
1 进程:进程就是正在执行的程序,每个进程执行都有一个执行顺序,该顺序就是一个控制单元或执行路径。
2 线程:线程就是进程中的一个独立的控制单元,线程控制着进程的执行。一个进程中至少有一个线程。
3 java虚拟机启动的时候会启动一个进程,该进程会有一个线程控制者程序的执行,线程执行的代码存在main函数中,该线程称为主线程。
4 多线程:一个进程能有多个线程,多线程能提高效率。
二 线程的几种状态:
(1)线程创建:创建Thread或Thread子类对象
(2)线程运行:具备运行资格,有执行权,方法start()
(3)线程阻塞:具备运行资格没有执行权
(4)线程冻结:没有执行资格,通过sleep(int time);wait();方法
(5)线程消亡:stop();程序结束
三 创建线程(两种方式)
1 继承Thread类,复写run()方法,线程运行的代码在run()方法中。调用start()方法执行线程。
(1)run()仅仅只是调用run()方法而没有执行线程
(2)start()执行线程并调用run()方法
例如:
class XianCheng extends Thread
{
public void run()
{
System.out.println("线程运行");
}
}
class ThreadDemo
{
public static void main(String[] args)
{
XianCheng xc=new XianCheng();//创建线程
xc.start();//执行线程
}
}
2.创建类实现Runnable接口,覆盖run()方法,创建Thread线程对象,并将Runnable接口子类对象作为参数传给Thread的构造方法,调用Thread对象start()方法
例如:
class XianCheng implements Runnable
{
public void run()
{
System.out.println("线程运行");
}
}
class ThreadDemo
{
public static void main(String[] args)
{
XianCheng xc=new XianCheng();//创建Runable子类对象
Thread t=new Thread(xc);//创建线程并将Runable的子类对象传进来
t.start();//执行线程
}
}
3 二种方式的区别
(1)继承Thread类方法,有继承的局限性,因为java只支持单继承。多线程运行的代码放在Thread类的子类的run()方法中。
(2)实现Runnable接口方法,java支持多实现,所以用这种方法提高了扩展性。此方法多线程运行的代码放在Runnable接口子类的run()方法中。
4 线程同步的方式
(1)同步代码块,同步代码块用的锁是任意对象都可以
格式:
synchronized(对象//任意对象)
{
需要被同步的语句;
}
(2)同步函数,将synchronized关键字放在函数的返回值前面,同步函数用的锁是this
静态同步函数,静态同步函数用的锁是该类的字节码文件对象 类名.class
线程同步例子:
class ThreadDemo
{
public static void main(String[] args)
{
//创建Runnable接口子类对象
SaleTicket st=new SaleTicket();
//创建线程将对象传给Thread类的构造方法
Thread t1=new Thread(st);
Thread t2=new Thread(st);
Thread t3=new Thread(st);
Thread t4=new Thread(st);
//线程执行
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class SaleTicket implements Runnable
{
//定义100张票
private int ticket=100;
//覆盖run()方法
public void run()
{
//无线循环
while(true)
{
//加同步,同步的锁是SaleTicket类的文件对象
synchronized(SaleTicket.class)
{
if(ticket>0)
{
//制作一个线程安全隐患
try{Thread.currentThread().sleep(5);} catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"正在售票第"+ticket--+"张票");
}
}
}
}
}
5 懒汉式的线程同步
代码如下:
class Single
{
private Single(){}//将构造函数私有不给外界创建对象
private static Single s=null;//本类创建对象,用静态修饰,方便getInstance()访问
public static Single getInstance()
{
//双层判断,只要s创建过对象就不再判断锁了,稍微高效
if(s==null)
{
//在这里加锁,防止多个线程同时执行下面的语句
synchronized(Single.class)
{
//如果为空,创建对象
if(s==null)
s=new Single();
}
}
return s;
}
}
6 死锁,同步中嵌套同步很容易发生死锁
代码示例:
public void run()
{
//如果一个线程执行if中代码,而另一个线程执行else代码
if(flag)
{
//此线程a锁中嵌套b锁
synchronized(Mylock.locka)
{
System.out.println("if locka");
synchronized(Mylock.lockb)
{
System.out.println("if lockb");
}
}
}
else
{
//此线程b锁中嵌套a锁,此时就很容易发生死锁
synchronized(Mylock.lockb)
{
System.out.println("else lockb");
synchronized(Mylock.locka)
{
System.out.println("else locka");
}
}
}
}
五 通信间的线程
1 Object中应用线程的方法
wait(),notify(),notifyAll()这些方法要使用在同步中。
2 定义在Object的原因
(1)这些方法在操作线程时,都必须标识他们所操作线程中的锁
(2)只有同一个锁上的线程等待,能被同一锁的线程唤醒
(3)而锁可以是任意对象,所以定义在Object中
3 等待中的线程在线程池中,一般线程唤醒的是线程中的第一个线程
例子:创建两个线程,一个负责赋值,一个赋值取值,操作同一资源对象。代码如下:
class ThreadDemo
{
public static void main(String[] args)
{
//创建资源对象
Res r=new Res();
//创建两个线程,一个负责给资源赋值,一个负责取值
new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
}
}
//定义一个资源类
class Res
{
private String name;
private String sex;
private boolean flag;
//同步函数
public synchronized void set(String name,String sex)
{
//判断标记,资源中没值就赋值,有值线程就等待
if(flag)
try{wait();} catch(Exception e){}
this.name=name;
this.sex=sex;
flag=true;//赋值之后把标记改为true,代表有值了
notify();//把对方唤醒
}
//同步函数
public synchronized void get()
{
//判断标记,资源中有值就取,没值线程就等待
if(!flag)
try{wait();} catch(Exception e){}
System.out.println(name+":::"+sex);
flag=false;//取值后把标记改为false
notify();//唤醒对方
}
}
//定义一个赋值的线程
class Input implements Runnable
{
//将资源传递给构造方法
private Res r;
Input(Res r)
{
this.r=r;
}
public void run()
{
int num=0;
while(true)
{
if(num==0)
r.set("lisi","man");
else
r.set("李四","男");
num=(num+1)%2;
}
}
}
//定义一个取值的线程
class Output implements Runnable
{
//将资源传递给构造方法
private Res r;
Output(Res r)
{
this.r=r;
}
public void run()
{
while(true)
{
r.get();
}
}
}
4 JDK1.5版本之后,提供了多线程升级解决方案
(1)将synchronized变为显示的Lock
(2)将Object中的wait(),notify(),notifyAll()替换成了Condition对象,更灵活的应用等待唤醒机制
六 操作线程的其他方法
1 停止线程:stop()(此方法已经过时),只有一种方法,就是run()方法结束,一般run()方法中,定义的都是循环语句,所以我们可以控制循环使线程结束。
2 中断线程:interrupt(),此方法可以将处于冻结状态的线程强制回到运行状态(清除线程的冻结状态)
3 守护线程:setDeamon()后台线程,当前台线程结束后,后台线程自动结束。此方法必须在线程执行前调用。
4 等待线程停止:jion()方法,放某个线程执行到join()方法时,该线程会冻结,等到调用join()方法的线程结束,该线程才回到运行状态。
5 优先级:setPriority(),此方法可以设置线程的优先级,优先级越高,CPU执行该线程的频率越高。默认是5。
6 yield():临时停止,暂停线程