------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
一:概述
进程:执行中的程序
每一个进程都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
线程: 进程中一个独立的控制单元。
线程在控制着进程的执行。
(一个进程中至少有一个线程)
eg: JVM启动的时候会有一个进程java.exe。该进程中至少有一个线程负责了java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称之为主线程
Thread 线程:程序中的执行线程。Java虚拟机允许应用程序并发的运行多个执行线程。
二:创建线程:
两种方法:
一:将类声明为Thread的子类,该子类应重写Thread类的run方法。接下来分配并启动该子类的实例。
二:声明实现Runnable接口的类,该类然后实现run方法。然后可以分配该类的实例,在创建Thread时作为一个参数来传递并启动。
start():使线程开始执行。java虚拟机调用该线程的run方法。
多线程具有随机性
run方法:存储线程要运行的代码
多窗口同时售票示例:
class J11_1
{
public static void main(String[] args)
{
//新建4个窗口
Ticket t1 = new Ticket();
Ticket t2 = new Ticket();
Ticket t3 = new Ticket();
Ticket t4 = new Ticket();
//开始窗口线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Ticket extends Thread
{
//票的总数为40
private static int num=40;
public void run()
{
while(true)
{
//将100张票全部卖出,并打印
if(num > 0)
{
System.out.println(currentThread().getName()+"sale:"+num--);
}
}
}
}
线程都有自己默认的名称:Thread-编号 该编号从0开始
currentThread():返回对当前正在执行的线程对象的引用
getName():获取线程名称
设置线程名称:setName()或者构造函数
Runnable接口:由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run的无参数方法。
实现方式好处:避免了单继承的局限性
继承方式:线程代码存放于Thread子类run方法中
实现方法:线程代码存放于接口的子类run方法中
售票例子的实现方法:
class J11_2
{
public static void main(String[] args)
{
Ticket k = new Ticket();
Thread t1 = new Thread(k);
Thread t2 = new Thread(k);
Thread t3 = new Thread(k);
Thread t4 = new Thread(k);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Ticket implements Runnable
{
private int num = 50;
Object obj = new Object();
public void run()
{
while(true)
{
synchronized(obj)
{
if(num>0)
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
}
System.out.println(Thread.currentThread().getName()+"sale:"+num--);
}
}
}
}
}
四:多线程的安全问题:
同步代码块:synchronized(对象){需要被同步的代码}
对象如同锁,持有锁的线程才可以在同步中运行。
同步的前提:
1,两个或两个以上的线程
2,必须是多个线程使用同一个锁
好处:解决了多线程的安全问题
弊端:多线程需要判断锁,较为耗费资源
同步函数:锁是this
静态同步函数:锁是class对象
(静态进内存时,内存中没有本类对象,但是一定会有该类对应的字节码文件对象。类名.class)
示例:用同步方法解决售票例子的安全隐患
class J11_4
{
public static void main(String[] args)
{
Ticket k = new Ticket();
Thread t1 = new Thread(k);
Thread t2 = new Thread(k);
// Thread t3 = new Thread(k);
// Thread t4 = new Thread(k);
t1.start();
try
{
Thread.sleep(10);
}
catch (Exception e)
{
}
k.flag = false;
t2.start();
// t3.start();
// t4.start();
}
}
class Ticket implements Runnable
{
private static int num = 100;
boolean flag = true;
//Object obj = new Object();
public void run()
{
if(flag)
{
while(true)
{
synchronized(Ticket.class)
{
if(num>0)
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
}
System.out.println(Thread.currentThread().getName()+" code "+"sale:"+num--);
}
}
}
}
else
while(true)
{
show();
}
}
static synchronized void show()
{
if(num>0)
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
}
System.out.println(Thread.currentThread().getName()+" show "+"sale:"+num--);
}
}
}
五:单例设计模式,死锁
死锁:同步中嵌套同步
示例:用同步方法解决懒汉式中的安全隐患
//懒汉式
class Single
{
private single(){}
private static Single s = null;
public static Single getInstance()
{
if(s==null)
{
synchronized (Single.class)
{
if(s==null)
s = new Single();
}
}
return s;
}
}
六:线程间通信
背景:多个线程应在操作同一个资源,但操作的功能不同
( JDK1.5中提供了多线程升级解决方案;
将同步synchronized替换成Lock操作;
将Object中的wait,notify,notifyAll替换成了Condition对象)
wait();notify();notifyAll():都是用在同步中,因为要对持有监视器(锁)的线程操作。
lock() 获取锁
unlock() 释放锁
newCondition():返回绑定到此Lock实例的新Condition实例
Condition接口:
await():造成当前线程在接到信号或被中断之前一直处于等待状态
signal():唤醒一个等待线程
signalAll():唤醒所有等待线程
输入输出线程通信示例:
class J12_1
{
public static void main(String[] args)
{
Res r = new Res();
Input i = new Input(r);
Output o = new Output(r);
Thread t1 = new Thread(i);
Thread t2 = new Thread(o);
t1.start();
t2.start();
}
}
class Res
{
private String name;
private String sex;
private boolean flag = false;
synchronized void set(String name,String sex)
{
if(flag)
try{this.wait();}catch(Exception e){}
this.name = name;
this.sex = sex;
flag = true;
this.notify();
}
synchronized void out()
{
if(flag)
{
System.out.println(name+"..."+sex);
flag =false;
this.notify();
}
else
try{this.wait();}catch(Exception e){}
}
}
class Input implements Runnable
{
private Res r;
int i = 0;
Input(Res r)
{
this.r = r;
}
public void run()
{
while (true)
{
if(i==0)
{
r.set("Mack","Man");
}
else
{
r.set("莉莉","女");
}
i=++i%2;
}
}
}
class Output implements Runnable
{
Res r;
Output(Res r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
}
七:停止线程,守护线程,优先级
停止线程:
1,定义循环结束标志
2,使用interrupt方法(结束冻结状态,使线程回到运行状态中来)
setDeamon(boolean on):将该线程标记为守护线程或用户线程
( 当正在运行的线程都是守护线程时,Java虚拟机退出;
该方法必须在启动线程前启用)
join()等待该线程终止
(当A线程执行到了B线程的.join()方法时,A就会等待,等B线程都执行完,A才会执行)
toString()返回该线程的字符串表示形式。包括线程名称,优先级和线程组。
setPriority(int newPriority)更改线程的优先级
yeild()暂停当前正在执行的线程对象,并执行其他线程。